diff -c -r --new-file ds1.1/lib/cfg/months.cfg ds2.1/lib/cfg/months.cfg *** ds1.1/lib/cfg/months.cfg Fri Jan 3 22:13:10 1997 --- ds2.1/lib/cfg/months.cfg Wed Jul 5 00:00:58 2006 *************** *** 5,17 **** # format: # month:season:days:day_length ! Roki:winter:20:9 ! Praxi:winter:20:10 ! Altki:spring:20:10 ! Ketralki:spring:20:10 ! Aenterki:summer:20:11 ! Kepki:summer:20:12 ! Kortki:summer:20:11 ! Kantki:autumn:20:10 ! Sartki:autumn:20:10 ! Denki:winter:20:10 --- 5,17 ---- # format: # month:season:days:day_length ! Roki:winter:20:11 ! Praxi:winter:20:12 ! Altki:spring:20:12 ! Ketralki:spring:20:12 ! Aenterki:summer:20:13 ! Kepki:summer:20:14 ! Kortki:summer:20:13 ! Kantki:autumn:20:12 ! Sartki:autumn:20:12 ! Denki:winter:20:12 diff -c -r --new-file ds1.1/lib/cfg/timezone.cfg ds2.1/lib/cfg/timezone.cfg *** ds1.1/lib/cfg/timezone.cfg Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cfg/timezone.cfg Wed Jul 5 00:00:58 2006 *************** *** 0 **** --- 1 ---- + EDT diff -c -r --new-file ds1.1/lib/cfg/timezones.cfg ds2.1/lib/cfg/timezones.cfg *** ds1.1/lib/cfg/timezones.cfg Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cfg/timezones.cfg Wed Jul 5 00:00:58 2006 *************** *** 0 **** --- 1,17 ---- + NZT + AET + AWT + MOT + CET + BST + GMT + ADT + AST + EDT + EST + CDT + CST + MDT + MST + PDT + PST diff -c -r --new-file ds1.1/lib/cmds/admins/arch.c ds2.1/lib/cmds/admins/arch.c *** ds1.1/lib/cmds/admins/arch.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/admins/arch.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,21 ---- + /* /cmds/creators/wiz.c + * Created by Zin@Frontiers + * Sun Sep 21 21:00:16 1997 EDT + */ + + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + write("You speed to the Arch room.\n"); + this_player()->eventMoveLiving("/secure/room/arch"); + return 1; + } + + void help() { + message("help", "Syntax: \n\n" + "This command will move you to the Arch room.\n\n", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/admins/broadcast.c ds2.1/lib/cmds/admins/broadcast.c *** ds1.1/lib/cmds/admins/broadcast.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/broadcast.c Wed Jul 5 00:01:03 2006 *************** *** 12,18 **** if(!archp(previous_object())) return 0; message("broadcast", sprintf("%%^RED%%^Broadcast message from %s: %%^YELLOW%%^%s%%^RESET%%^", ! (string)this_player()->GetName(), str), users()); return 1; } --- 12,18 ---- if(!archp(previous_object())) return 0; message("broadcast", sprintf("%%^RED%%^Broadcast message from %s: %%^YELLOW%%^%s%%^RESET%%^", ! (string)this_player()->GetName(), str), users()); return 1; } diff -c -r --new-file ds1.1/lib/cmds/admins/cache.c ds2.1/lib/cmds/admins/cache.c *** ds1.1/lib/cmds/admins/cache.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/cache.c Wed Jul 5 00:01:03 2006 *************** *** 5,23 **** int cmd(string arg) { ! if(!archp(previous_object())) return 0; ! cache_stats(); ! return 1; } int help() { ! write( @EndText Syntax: cache Effect: Gets the cache stats from the driver, including the hit rate See man: cache_stats See also: callouts, mstatus, netstat, opcprof, fdinfo, dumpallobj EndText ! ); ! return 1; } --- 5,23 ---- int cmd(string arg) { ! if(!archp(previous_object())) return 0; ! cache_stats(); ! return 1; } int help() { ! write( @EndText Syntax: cache Effect: Gets the cache stats from the driver, including the hit rate See man: cache_stats See also: callouts, mstatus, netstat, opcprof, fdinfo, dumpallobj EndText ! ); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/admins/channel.c ds2.1/lib/cmds/admins/channel.c *** ds1.1/lib/cmds/admins/channel.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/channel.c Wed Jul 5 00:01:03 2006 *************** *** 13,67 **** if(!str) return 0; if(!archp(previous_object())) return 0; ! // Attempt to remove or add a players line rights. if(sscanf(str, "%s %s %s", opt, who, channel) == 3) { ! if(!(ob = find_player(lower_case(who)))) ! return notify_fail("No such player online.\n"); ! if(opt == "remove") { ! if(member_array(channel, ob->GetChannels()) == -1) { ! this_player()->eventPrint(ob->GetName() ! + " is not currently subscribed to the " + channel + " line."); ! return 1; ! } ! ob->RestrictChannel(channel); ! this_player()->eventPrint("%^RED%^You restrict " + ob->GetName() ! + " from the " + channel + " line.%^RESET%^"); ! ob->eventPrint("%^RED%^You have lost your " + channel ! + " line rights.%^RESET%^"); ! return 1; ! } ! else if(opt == "add") { ! if(member_array(channel, ob->GetRestrictedChannels()) == -1) { ! message("system", ob->GetName() + " is not currently restricted from the " ! + channel + " line.", this_player()); ! return 1; ! } ! ob->UnrestrictChannel(channel); ! this_player()->eventPrint("%^RED%^You unrestrict " + ob->GetName() ! + " from the " + channel + " line.%^RESET%^"); ! ob->eventPrint("%^RED%^You have regained your " + channel ! + " line rights.%^RESET%^"); ! return 1; ! } } // Otherwise, return restriction information, if it is requested. else if(str) { ! string *channels; ! string tmp; ! int size; ! if(!(ob = find_player(lower_case(str)))) ! return notify_fail("No such player online.\n"); ! channels = ob->GetRestrictedChannels(); ! size = sizeof(channels); ! tmp = ob->GetName() + " is currently restricted from "; ! if(size) tmp += "the " + conjunction(channels); ! else tmp += "no"; ! if(size == 1) tmp += " line."; ! else tmp += " lines."; ! this_player()->eventPrint(tmp); ! return 1; } else return 0; } --- 13,67 ---- if(!str) return 0; if(!archp(previous_object())) return 0; ! // Attempt to remove or add a players line rights. if(sscanf(str, "%s %s %s", opt, who, channel) == 3) { ! if(!(ob = find_player(lower_case(who)))) ! return notify_fail("No such player online.\n"); ! if(opt == "remove") { ! if(member_array(channel, ob->GetChannels()) == -1) { ! this_player()->eventPrint(ob->GetName() ! + " is not currently subscribed to the " + channel + " line."); ! return 1; ! } ! ob->RestrictChannel(channel); ! this_player()->eventPrint("%^RED%^You restrict " + ob->GetName() ! + " from the " + channel + " line.%^RESET%^"); ! ob->eventPrint("%^RED%^You have lost your " + channel ! + " line rights.%^RESET%^"); ! return 1; ! } ! else if(opt == "add") { ! if(member_array(channel, ob->GetRestrictedChannels()) == -1) { ! message("system", ob->GetName() + " is not currently restricted from the " ! + channel + " line.", this_player()); ! return 1; ! } ! ob->UnrestrictChannel(channel); ! this_player()->eventPrint("%^RED%^You unrestrict " + ob->GetName() ! + " from the " + channel + " line.%^RESET%^"); ! ob->eventPrint("%^RED%^You have regained your " + channel ! + " line rights.%^RESET%^"); ! return 1; ! } } // Otherwise, return restriction information, if it is requested. else if(str) { ! string *channels; ! string tmp; ! int size; ! if(!(ob = find_player(lower_case(str)))) ! return notify_fail("No such player online.\n"); ! channels = ob->GetRestrictedChannels(); ! size = sizeof(channels); ! tmp = ob->GetName() + " is currently restricted from "; ! if(size) tmp += "the " + conjunction(channels); ! else tmp += "no"; ! if(size == 1) tmp += " line."; ! else tmp += " lines."; ! this_player()->eventPrint(tmp); ! return 1; } else return 0; } diff -c -r --new-file ds1.1/lib/cmds/admins/dumpallobj.c ds2.1/lib/cmds/admins/dumpallobj.c *** ds1.1/lib/cmds/admins/dumpallobj.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/dumpallobj.c Wed Jul 5 00:01:03 2006 *************** *** 5,23 **** int cmd(string arg) { ! if(!archp(previous_object())) return 0; ! dumpallobj("/tmp/objects"); ! return 1; } int help() { ! write( @EndText Syntax: dumpallobj Effect: Puts a list of all currently loaded objects in /log/dumps/obj_dump See man: dumpallobj See also: callouts, cache, mstatus, netstat, fdinfo, opcprof EndText ! ); ! return 1; } --- 5,23 ---- int cmd(string arg) { ! if(!archp(previous_object())) return 0; ! dumpallobj("/tmp/objects"); ! return 1; } int help() { ! write( @EndText Syntax: dumpallobj Effect: Puts a list of all currently loaded objects in /log/dumps/obj_dump See man: dumpallobj See also: callouts, cache, mstatus, netstat, fdinfo, opcprof EndText ! ); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/admins/fdinfo.c ds2.1/lib/cmds/admins/fdinfo.c *** ds1.1/lib/cmds/admins/fdinfo.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/fdinfo.c Wed Jul 5 00:01:03 2006 *************** *** 5,23 **** int cmd(string arg) { ! if(!archp(previous_object())) return 0; ! dump_file_descriptors(); ! return 1; } int help() { ! write( @EndText Syntax: fdinfo Effect: Lists the status of the machines's file descriptors See man: dump_file_descriptors See also: netstat, mstatus, cache, callouts, dumpallobj, opcprof EndText ! ); ! return 1; } --- 5,23 ---- int cmd(string arg) { ! if(!archp(previous_object())) return 0; ! dump_file_descriptors(); ! return 1; } int help() { ! write( @EndText Syntax: fdinfo Effect: Lists the status of the machines's file descriptors See man: dump_file_descriptors See also: netstat, mstatus, cache, callouts, dumpallobj, opcprof EndText ! ); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/admins/mfinger.c ds2.1/lib/cmds/admins/mfinger.c *** ds1.1/lib/cmds/admins/mfinger.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/mfinger.c Sat Jul 8 23:30:54 2006 *************** *** 23,29 **** if( !args || args == "" ) return "Mfinger whom?"; if( !(ob = find_player(args)) ) ! return "No one around " + mud_name() + " by that name."; ip = query_ip_number(ob); args = (string)ob->GetCapName(); ob = new(LIB_CLIENT); --- 23,29 ---- if( !args || args == "" ) return "Mfinger whom?"; if( !(ob = find_player(args)) ) ! return "No one around " + mud_name() + " by that name."; ip = query_ip_number(ob); args = (string)ob->GetCapName(); ob = new(LIB_CLIENT); *************** *** 37,43 **** ob->SetRead( (: ReadSocket :) ); ob->eventWrite("\n"); message("system", "Finger sent to " + possessive_noun(args) + " site " + ! ip + ".", this_player()); return 1; } --- 37,43 ---- ob->SetRead( (: ReadSocket :) ); ob->eventWrite("\n"); message("system", "Finger sent to " + possessive_noun(args) + " site " + ! ip + ".", this_player()); return 1; } *************** *** 47,58 **** if( !Waiting[ob = previous_object()] ) return; if( !Waiting[ob]["who"] ) return; message("system", "Information from " + Waiting[ob]["ip"] + " for " + ! Waiting[ob]["player"] + ":", Waiting[ob]["who"]); message("system", str, Waiting[ob]["who"]); } void help() { message("help", "Syntax: \n\n" ! "Allows you to get finger information from a player's site.", ! this_player()); } --- 47,63 ---- if( !Waiting[ob = previous_object()] ) return; if( !Waiting[ob]["who"] ) return; message("system", "Information from " + Waiting[ob]["ip"] + " for " + ! Waiting[ob]["player"] + ":", Waiting[ob]["who"]); message("system", str, Waiting[ob]["who"]); } void help() { message("help", "Syntax: \n\n" ! "Allows you to get finger information from a player's site.\n\n" ! "Note: In 1995, you could reliably expect a UNIX machine to cheerfully " ! "respond to a finger request. Now, more than 10 years later, everything " ! "is blocked, firewalled, and hardened. This command is all but useless, " ! "and is kept as a historical curiosity. Any \"bugs\" it contains will " ! "not be fixed.", ! this_player()); } diff -c -r --new-file ds1.1/lib/cmds/admins/objload.c ds2.1/lib/cmds/admins/objload.c *** ds1.1/lib/cmds/admins/objload.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/objload.c Wed Jul 5 00:01:03 2006 *************** *** 30,36 **** } foreach(string who, mixed array data in vals) { mapping mp = ([]); ! output += ({ who + ": " + data[0] }); foreach(object ob in data[1]) { mp[base_name(ob)]++; --- 30,36 ---- } foreach(string who, mixed array data in vals) { mapping mp = ([]); ! output += ({ who + ": " + data[0] }); foreach(object ob in data[1]) { mp[base_name(ob)]++; *************** *** 45,52 **** string GetHelp(string unused) { return ("Syntax: \n\n" ! "Provides you with information about how many objects " ! "each creator has in the game."); } ! ! --- 45,52 ---- string GetHelp(string unused) { return ("Syntax: \n\n" ! "Provides you with information about how many objects " ! "each creator has in the game."); } ! ! diff -c -r --new-file ds1.1/lib/cmds/admins/opcprof.c ds2.1/lib/cmds/admins/opcprof.c *** ds1.1/lib/cmds/admins/opcprof.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/admins/opcprof.c Wed Dec 31 19:00:00 1969 *************** *** 1,28 **** - #include - - - inherit LIB_DAEMON; - - int - cmd(string arg) - { - if(!archp(previous_object())) return 0; - #ifdef HAS_OPCPROF - opcprof(LOG_DIR + "/dumps/opcprof"); - #else - message("my_action","Sorry, driver has been compiled with OPC_PROF disabled",this_player()); - #endif - return 1; - } - - int help() - { - write( @EndText - Syntax: opcprof - Effect: Puts a list of efuns and eoperators in /log/dumps/opcprof - See man: opcprof - See also: fdinfo, netstat, mstatus, cache, callouts, dumpallobj, - EndText - ); - return 1; - } --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/common/help.c ds2.1/lib/cmds/common/help.c *** ds1.1/lib/cmds/common/help.c Sun Feb 1 21:29:49 1998 --- ds2.1/lib/cmds/common/help.c Wed Jul 5 00:01:03 2006 *************** *** 16,33 **** mixed cmd(string arg) { object who = previous_object(); int array screen = (who->GetScreen() || ({ 80, 24 })); ! string help; ! ! if( !arg ) { ! help = center("Dead Souls System Help", screen[0]); ! help += wrap(HELP_D->GetHelp(0), screen[0]); ! who->eventPage(explode(help, "\n"), MSG_HELP, function() { ! this_player()->eventPrint("Hit the key to get a list of indices," ! "'q' to quit help: ", MSG_PROMPT); ! input_to(function(string str) { ! if( str == "q" ) return; ! HelpMenu(); }); ! }); return 1; } if( arg == "index" || HELP_D->GetTopics(arg) ) { --- 16,33 ---- mixed cmd(string arg) { object who = previous_object(); int array screen = (who->GetScreen() || ({ 80, 24 })); ! string help = ""; ! ! if( arg == "help") { ! help = HELP_D->GetHelp("help"); ! write(help); ! return 1; ! } ! if( !arg || arg == "") { ! if(creatorp(this_player())) help = read_file("/doc/help/creators/creator_general"); ! else help = read_file("/doc/help/players/player_general"); ! if(!sizeof(help)) help = HELP_D->GetHelp("help"); ! write(help); return 1; } if( arg == "index" || HELP_D->GetTopics(arg) ) { *************** *** 41,48 **** if( !(help = HELP_D->GetHelp(arg)) ) { return HELP_D->GetLastError(); } ! help = center("Dead Souls System Help", screen[0]) + help; ! help = wrap(help, screen[0]); who->eventPage(explode(help, "\n"), MSG_HELP); return 1; } --- 41,48 ---- if( !(help = HELP_D->GetHelp(arg)) ) { return HELP_D->GetLastError(); } ! help = center(mud_name()+" System Help", screen[0]) + help; ! if(sizeof(help) < 2000) help = wrap(help, screen[0]); who->eventPage(explode(help, "\n"), MSG_HELP); return 1; } *************** *** 57,161 **** string array indices; int array scr; int y = 0; ! scr = this_player()->GetScreen() || ({ 80, 25 }); ! tmp = center("Dead Souls System Help", scr[0]); if( !index ) { tmp += "Index: %^GREEN%^main index%^RESET%^\n\n"; indices = filter(HELP_D->GetIndices(), ! (: CanAccess(this_player(), $1) :)); foreach(string yuck in indices) { int z = strlen(yuck) + 6; ! if( z > y ) { y = z; } } tmp += format_page(map(indices, function(string str, string array ind) { ! int num = member_array(str, ind) + 1; ! return ("[%^CYAN%^"+(num)+"%^RESET%^] " + str); ! }, indices), scr[0]/(y+2)); } else if( !HELP_D->CanAccess(this_player(), index) ) { message("help", "Invalid index choice.", this_player()); message("prompt", "Hit : ", this_player()); input_to(function(string str) { HelpMenu(0); }); ! return; ! } ! else { ! string array topics = HELP_D->GetTopics(index); ! string array bing = allocate(sizeof(topics)); ! int i = 0; ! ! tmp += "Index: %^GREEN%^" + index + "%^RESET%^\n\n"; ! foreach(string topic in topics) { ! int z = strlen(topic) + 6; ! ! if( z > y ) { ! y = z; ! } ! bing[i++] = "[%^CYAN%^" + (i+1) + "%^RESET%^] " + topic; ! } ! tmp += format_page(bing, scr[0]/(y+2)); ! } ! f = function(string ind) { ! if( !ind ) ! message("prompt", "\n\nEnter a index or 'q' to quit help: ", ! this_player()); ! else ! message("prompt", "\n\nEnter a topic, 'q' to quit help, or " ! " for main menu: ", this_player()); ! input_to(function(string str, string ind) { ! string ret; ! int ind_num; ! int *scr; ! ! if( str == "q" ) { ! message("system", "Exiting help.", this_player()); ! return; ! } ! if( !str || str == "" ) { ! HelpMenu(0); ! return; ! } ! scr = (int *)this_player()->GetScreen() || ({ 80 }); ! if( ind_num = to_int(str) ) { ! string array tmp2; ! if( !ind ) tmp2 = filter(HELP_D->GetIndices(), ! (: CanAccess(this_player(), $1) :)); ! else tmp2 = HELP_D->GetTopics(ind); ! if( ind_num < 1 || ind_num > sizeof(tmp2) ) { ! str = 0; ! HELP_D->SetError("Index number out of range."); } ! else str = tmp2[ind_num - 1]; ! } ! if( !ind && !HELP_D->GetTopics(str) ) { ! message("help", "Invalid index choice.", this_player()); ! message("prompt", "Hit : ", this_player()); ! input_to(function(string str) { HelpMenu(); }); ! return; } ! else if( !ind ) { ! HelpMenu(str); ! return; ! } ! if( !(ret = HELP_D->GetHelpByIndex(ind, str)) ) { ! message("help", HELP_D->GetLastError(), this_player()); ! message("prompt", "\nHit : ", this_player()); ! input_to(function(string str) { HelpMenu(); }); ! return; ! } ! ret = center("Dead Souls System Help", scr[0])+wrap(ret, scr[0]); ! this_player()->eventPage(explode(ret, "\n"), "help", ! function(string ind) { ! message("prompt", "\n\nHit : ", ! this_player()); ! input_to(function(string str, string ind) { ! HelpMenu(ind); }, ind); ! return; ! }, ind); ! }, ind); ! }; ! this_player()->eventPage(explode(tmp, "\n"), "help", f, index); ! } --- 57,161 ---- string array indices; int array scr; int y = 0; ! scr = this_player()->GetScreen() || ({ 80, 25 }); ! tmp = center(mud_name()+" System Help", scr[0]); if( !index ) { tmp += "Index: %^GREEN%^main index%^RESET%^\n\n"; indices = filter(HELP_D->GetIndices(), ! (: CanAccess(this_player(), $1) :)); foreach(string yuck in indices) { int z = strlen(yuck) + 6; ! if( z > y ) { y = z; } } tmp += format_page(map(indices, function(string str, string array ind) { ! int num = member_array(str, ind) + 1; ! return ("[%^CYAN%^"+(num)+"%^RESET%^] " + str); ! }, indices), scr[0]/(y+2)); } else if( !HELP_D->CanAccess(this_player(), index) ) { message("help", "Invalid index choice.", this_player()); message("prompt", "Hit : ", this_player()); input_to(function(string str) { HelpMenu(0); }); ! return; ! } ! else { ! string array topics = HELP_D->GetTopics(index); ! string array bing = allocate(sizeof(topics)); ! int i = 0; ! ! tmp += "Index: %^GREEN%^" + index + "%^RESET%^\n\n"; ! foreach(string topic in topics) { ! int z = strlen(topic) + 6; ! ! if( z > y ) { ! y = z; } ! bing[i++] = "[%^CYAN%^" + (i+1) + "%^RESET%^] " + topic; } ! tmp += format_page(bing, scr[0]/(y+2)); ! } ! f = function(string ind) { ! if( !ind ) ! message("prompt", "\n\nEnter a index or 'q' to quit help: ", ! this_player()); ! else ! message("prompt", "\n\nEnter a topic, 'q' to quit help, or " ! " for main menu: ", this_player()); ! input_to(function(string str, string ind) { ! string ret; ! int ind_num; ! int *scr; ! ! if( str == "q" ) { ! message("system", "Exiting help.", this_player()); ! return; ! } ! if( !str || str == "" ) { ! HelpMenu(0); ! return; ! } ! scr = (int *)this_player()->GetScreen() || ({ 80 }); ! if( ind_num = to_int(str) ) { ! string array tmp2; ! if( !ind ) tmp2 = filter(HELP_D->GetIndices(), ! (: CanAccess(this_player(), $1) :)); ! else tmp2 = HELP_D->GetTopics(ind); ! if( ind_num < 1 || ind_num > sizeof(tmp2) ) { ! str = 0; ! HELP_D->SetError("Index number out of range."); ! } ! else str = tmp2[ind_num - 1]; ! } ! if( !ind && !HELP_D->GetTopics(str) ) { ! message("help", "Invalid index choice.", this_player()); ! message("prompt", "Hit : ", this_player()); ! input_to(function(string str) { HelpMenu(); }); ! return; ! } ! else if( !ind ) { ! HelpMenu(str); ! return; ! } ! if( !(ret = HELP_D->GetHelpByIndex(ind, str)) ) { ! message("help", HELP_D->GetLastError(), this_player()); ! message("prompt", "\nHit : ", this_player()); ! input_to(function(string str) { HelpMenu(); }); ! return; ! } ! ret = center(mud_name()+" System Help", scr[0])+wrap(ret, scr[0]); ! this_player()->eventPage(explode(ret, "\n"), "help", ! function(string ind) { ! message("prompt", "\n\nHit : ", ! this_player()); ! input_to(function(string str, string ind) { ! HelpMenu(ind); }, ind); ! return; ! }, ind); ! }, ind); ! }; ! this_player()->eventPage(explode(tmp, "\n"), "help", f, index); ! } diff -c -r --new-file ds1.1/lib/cmds/creators/anglicize.c ds2.1/lib/cmds/creators/anglicize.c *** ds1.1/lib/cmds/creators/anglicize.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/anglicize.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,41 ---- + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + object target; + + if(!str || str == "") str = "me"; + + if(str == "me") str = this_player()->GetKeyName(); + if(!target = present(str, environment(this_player()))){ + write("They're not here."); + return 1; + } + if(!living(target)) { + write("That's not a living thing."); + return 1; + } + if(creatorp(target) && !archp(this_player()) && + target != this_player()){ + write("That's impolite."); + tell_player(target,capitalize(this_player()->GetKeyName())+ + " just tried to anglicize you."); + return 1; + } + + target->SetNativeLanguage("English"); + if(target == this_player()) str = "yourself"; + else str = capitalize(str); + write("You anglicize "+str+"."); + if(target != this_player()) + tell_object(target, capitalize(this_player()->GetKeyName())+" anglicizes you."); + return 1; + } + + void help() { + message("help", "Syntax: anglicize \n\n" + "Make the target's native language English.\n\n", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/ascii.c ds2.1/lib/cmds/creators/ascii.c *** ds1.1/lib/cmds/creators/ascii.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/ascii.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,41 ---- + #include + #include + + inherit LIB_COMMAND; + + int cmd(string str){ + int code; + string tmp; + string ret = ""; + + if(str && !code = atoi(str)){ + write("That doesn't appear to be an integer."); + return 1; + } + + if(code) { + ret = convert_ascii(code); + write("The ASCII code "+code+" is: "+ret); + return 1; + } + + for(code = 33; code < 256; code++){ + tmp = convert_ascii(code); + if(sizeof(tmp)) ret += "The ASCII code "+code+" is: "+tmp+"\n"; + } + + write(ret); + return 1; + } + + + + string GetHelp(string str) { + return "Syntax: ascii [CODE]\n" + "Provided an integer that corresponds to an ASCII code known to " + "the mud, that character will be displayed. Note that the mud's " + "understanding of these characters is imperfect, and your client's " + "rendition may be unsatisfactory.\nWithout an argument, the command " + "displays all ASCII codes known to the mud and their characters.\n " + ""; + } diff -c -r --new-file ds1.1/lib/cmds/creators/boards.c ds2.1/lib/cmds/creators/boards.c *** ds1.1/lib/cmds/creators/boards.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/boards.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,28 ---- + // By Magnafix 10-14-96 + // required addition of list_new_posts() in bboard daemon + #include + #include + + inherit LIB_COMMAND; + + + int cmd(string str){ + string *boards; + int x; + + boards = ({ "immortal_board" }); + if(archp(this_player())) boards += ({ "admin_board" }); + + for(x = 0; x < sizeof(boards); x++) + write("/secure/daemon/bboard.c"->list_new_posts(boards[x])); + + return 1; + } + + + + string GetHelp(string str) { + return "Syntax: \n" + "This command tells you which boards have unread messages " + "on them."; + } diff -c -r --new-file ds1.1/lib/cmds/creators/callouts.c ds2.1/lib/cmds/creators/callouts.c *** ds1.1/lib/cmds/creators/callouts.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/callouts.c Wed Jul 5 00:01:03 2006 *************** *** 14,20 **** mixed cmd(string args) { mixed array callouts; string tmp; ! callouts = call_out_info(); if( !sizeof(callouts) ) { previous_object()->eventPrint("No pending callouts.", MSG_SYSTEM); --- 14,20 ---- mixed cmd(string args) { mixed array callouts; string tmp; ! callouts = call_out_info(); if( !sizeof(callouts) ) { previous_object()->eventPrint("No pending callouts.", MSG_SYSTEM); *************** *** 22,28 **** } tmp = sprintf("%:-40s %:-25s Delay\n", "Object", "Function"); tmp += "--------------------------------------------------" ! "-------------------------\n"; foreach(mixed array callout in callouts) { tmp += sprintf("%:-40O %:-25s %d\n", callout...); } --- 22,28 ---- } tmp = sprintf("%:-40s %:-25s Delay\n", "Object", "Function"); tmp += "--------------------------------------------------" ! "-------------------------\n"; foreach(mixed array callout in callouts) { tmp += sprintf("%:-40O %:-25s %d\n", callout...); } *************** *** 32,37 **** string GetHelp() { return ("Syntax: \n\n" ! "Lists all pending callouts.\n\n" ! "See also: events, mstatus, netstat"); } --- 32,37 ---- string GetHelp() { return ("Syntax: \n\n" ! "Lists all pending callouts.\n\n" ! "See also: events, mstatus, netstat"); } diff -c -r --new-file ds1.1/lib/cmds/creators/classblock.c ds2.1/lib/cmds/creators/classblock.c *** ds1.1/lib/cmds/creators/classblock.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/classblock.c Wed Jul 5 00:01:03 2006 *************** *** 12,18 **** #include inherit LIB_DAEMON; ! mixed cmd(string args) { if( !args || (args != "on" && args != "off") ) { return "Syntax: "; --- 12,18 ---- #include inherit LIB_DAEMON; ! mixed cmd(string args) { if( !args || (args != "on" && args != "off") ) { return "Syntax: "; *************** *** 24,30 **** } } previous_object()->eventPrint("You are now blocking all class lines.", ! MSG_SYSTEM); } else { foreach(string class_name in CLASSES_D->GetClasses()) { --- 24,30 ---- } } previous_object()->eventPrint("You are now blocking all class lines.", ! MSG_SYSTEM); } else { foreach(string class_name in CLASSES_D->GetClasses()) { *************** *** 33,46 **** } } previous_object()->eventPrint("You are no longer blocking any class " ! "lines.", MSG_SYSTEM); } return 1; } ! string GetHelp() { return ("Syntax: \n\n" ! "Allows you to make sure that you are blocking all or no " ! "class chat lines.\n\n" ! "See also: codeblock"); } --- 33,46 ---- } } previous_object()->eventPrint("You are no longer blocking any class " ! "lines.", MSG_SYSTEM); } return 1; } ! string GetHelp() { return ("Syntax: \n\n" ! "Allows you to make sure that you are blocking all or no " ! "class chat lines.\n\n" ! "See also: codeblock"); } diff -c -r --new-file ds1.1/lib/cmds/creators/clean.c ds2.1/lib/cmds/creators/clean.c *** ds1.1/lib/cmds/creators/clean.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/clean.c Wed Jul 5 00:01:03 2006 *************** *** 14,20 **** mixed cmd(string args) { object array obs, items, users; object ob; ! if( !args || args == "" ) { ob = environment(previous_object()); } --- 14,20 ---- mixed cmd(string args) { object array obs, items, users; object ob; ! if( !args || args == "" ) { ob = environment(previous_object()); } *************** *** 45,53 **** string GetHelp() { return ("Syntax: \n" ! " \n\n" ! "This command destroys all objects in the inventory of a " ! "specified object. It skips any item that has a user somewhere " ! "in its deep inventory."); } --- 45,53 ---- string GetHelp() { return ("Syntax: \n" ! " \n\n" ! "This command destroys all objects in the inventory of a " ! "specified object. It skips any item that has a user somewhere " ! "in its deep inventory."); } diff -c -r --new-file ds1.1/lib/cmds/creators/clone.c ds2.1/lib/cmds/creators/clone.c *** ds1.1/lib/cmds/creators/clone.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/clone.c Wed Jul 5 00:01:03 2006 *************** *** 17,47 **** if( args == "" || !args ) return "Clone what?"; file = absolute_path((string)this_player()->query_cwd(), args); if( file[<2..] != ".c" ) file = file + ".c"; ! if( file_size(file) < 0 ) return "No such file " + file; if( res = catch(ob = new(file)) ) ! return "Error in cloning object: " + res; if( !ob ) return "Failed to clone file: " + file; if( !((int)ob->eventMove(this_player())) && ! !((int)ob->eventMove(environment(this_player()))) ) { message("system", "Failed to properly move the object.", ! this_player()); return 1; } if( !(nom = (string)ob->GetShort()) ) nom = "something peculiar"; if( !(res = (string)this_player()->GetMessage("clone", ob)) ) ! res = (string)this_player()->GetName() + " clones " + nom + "."; message("info", "You clone " + nom + " (" + file + ").", ! this_player()); message("other_action", res, environment(this_player()), ! ({ this_player() })); return 1; } string GetHelp() { return ("Syntax: \n\n" ! "Clones the object from the code stored in the file named. " ! "If for some reason the object cannot be moved to your " ! "inventory (it is alive, you cannot carry it, etc.), then " ! "it will be moved into your environment.\n\n" ! "See also: dest, message"); } --- 17,47 ---- if( args == "" || !args ) return "Clone what?"; file = absolute_path((string)this_player()->query_cwd(), args); if( file[<2..] != ".c" ) file = file + ".c"; ! if( file_size(file) < 0 && !archp(this_player())) return "No such file " + file; if( res = catch(ob = new(file)) ) ! return "Error in cloning object: " + res; if( !ob ) return "Failed to clone file: " + file; if( !((int)ob->eventMove(this_player())) && ! !((int)ob->eventMove(environment(this_player()))) ) { message("system", "Failed to properly move the object.", ! this_player()); return 1; } if( !(nom = (string)ob->GetShort()) ) nom = "something peculiar"; if( !(res = (string)this_player()->GetMessage("clone", ob)) ) ! res = (string)this_player()->GetName() + " clones " + nom + "."; message("info", "You clone " + nom + " (" + file + ").", ! this_player()); message("other_action", res, environment(this_player()), ! ({ this_player() })); return 1; } string GetHelp() { return ("Syntax: \n\n" ! "Clones the object from the code stored in the file named. " ! "If for some reason the object cannot be moved to your " ! "inventory (it is alive, you cannot carry it, etc.), then " ! "it will be moved into your environment.\n\n" ! "See also: dest, message"); } diff -c -r --new-file ds1.1/lib/cmds/creators/codeblock.c ds2.1/lib/cmds/creators/codeblock.c *** ds1.1/lib/cmds/creators/codeblock.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/codeblock.c Wed Jul 5 00:01:03 2006 *************** *** 15,21 **** previous_object()->SetBlocked("all"); if( previous_object()->GetBlocked("all") ) { previous_object()->eventPrint("All channels are being blocked.", ! MSG_SYSTEM); } else { previous_object()->eventPrint("Codeblock is now off.", MSG_SYSTEM); --- 15,21 ---- previous_object()->SetBlocked("all"); if( previous_object()->GetBlocked("all") ) { previous_object()->eventPrint("All channels are being blocked.", ! MSG_SYSTEM); } else { previous_object()->eventPrint("Codeblock is now off.", MSG_SYSTEM); *************** *** 25,31 **** string GetHelp() { return ("Syntax: \n\n" ! "Allows you to toggle on and off the blocking of all mud " ! "channels.\n\n" ! "See also: classblock"); } --- 25,31 ---- string GetHelp() { return ("Syntax: \n\n" ! "Allows you to toggle on and off the blocking of all mud " ! "channels.\n\n" ! "See also: classblock"); } diff -c -r --new-file ds1.1/lib/cmds/creators/colors.c ds2.1/lib/cmds/creators/colors.c *** ds1.1/lib/cmds/creators/colors.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/colors.c Sat Jul 8 23:30:54 2006 *************** *** 0 **** --- 1,40 ---- + #include + #include + + inherit LIB_DAEMON; + + int cmd() { + + write( + "%^RED%^RED\t%%^^RED%%^^\n" + "%^GREEN%^GREEN\t%%^^GREEN%%^^\n" + "%^ORANGE%^ORANGE\t%%^^ORANGE%%^^\n" + "%^YELLOW%^YELLOW\t%%^^YELLOW%%^^\n" + "%^BLUE%^BLUE\t%%^^BLUE%%^^\n" + "%^CYAN%^CYAN\t%%^^CYAN%%^^\n" + "%^MAGENTA%^MAGENTA\t%%^^MAGENTA%%^^\n" + "%^BLACK%^BLACK\t%%^^BLACK%%^^\n" + "%^WHITE%^WHITE\t%%^^WHITE%%^^\n" + "%^B_RED%^B_RED\t%%^^B_RED%%^^\n" + "%^B_GREEN%^B_GREEN\t%%^^B_GREEN%%^^\n" + "%^B_ORANGE%^B_ORANGE\t%%^^B_ORANGE%%^^\n" + "%^B_YELLOW%^B_YELLOW\t%%^^B_YELLOW%%^^\n" + "%^B_BLUE%^B_BLUE\t%%^^B_BLUE%%^^\n" + "%^B_CYAN%^B_CYAN\t%%^^B_CYAN%%^^\n" + "%^B_BLACK%^B_BLACK\t%%^^B_BLACK%%^^\n" + "%^B_WHITE%^B_WHITE\t%%^^B_WHITE%%^^\n" + "%^B_MAGENTA%^B_MAGENTA%^RESET%^\n\n" + "Special tags: %%^^BOLD%%^^ and %%^^FLASH%%^^ and %%^^RESET%%^^\n\n" + "You can mix and match, for example: \n" + "%%^^B_RED%%^^%%^^CYAN%%^^%%^^BOLD%%^^%%^^FLASH%%^^Foo!%%^^RESET%%^^:" + "%^B_RED%^%^CYAN%^%^BOLD%^%^FLASH%^Foo!%^RESET%^" + ); + return 1; + } + + string GetHelp() { + return("Syntax: colors\n\n" + "Lists all available colors in the corresponding color." + "\n\n"); + } + diff -c -r --new-file ds1.1/lib/cmds/creators/debug.c ds2.1/lib/cmds/creators/debug.c *** ds1.1/lib/cmds/creators/debug.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/debug.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,25 ---- + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + int status = this_player()->GetProperty("debug"); + if(!str && !status) str = "on"; + else if(!str && status) str = "off"; + if(str != "on" && str != "off") return 0; + if(str == "on"){ + write("You enable debugging."); + this_player()->SetProperty("debug", 1); + return 1; + } + write("You disable debugging."); + this_player()->SetProperty("debug", 0); + return 1; + } + + void help() { + message("help", "Syntax: debug [on | off]\n\n" + "Allows you to receive debugging information\n\n", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/dest.c ds2.1/lib/cmds/creators/dest.c *** ds1.1/lib/cmds/creators/dest.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/dest.c Wed Dec 31 19:00:00 1969 *************** *** 1,67 **** - /* /cmds/creator/dest.c - * From the Dead Souls V Object Library - * Destructs the object named - * Created by Descartes of Borg 950425 - * Version: @(#) dest.c 1.2@(#) - * Last modified: 96/10/08 - */ - - #include - #include - - inherit LIB_DAEMON; - - mixed cmd(string args) { - object who = previous_object(); - object target; - string msg; - - if( !args || args == "" ) { - return "Dest what?"; - } - if( args == "all" ) { - foreach(target in all_inventory(environment(who))) { - if( interactive(target) ) { - continue; - } - msg = who->GetMessage("dest", target); - who->eventPrint("You dest " + target->GetShort() + ".", - MSG_SYSTEM); - environment(who)->eventPrint(msg, MSG_SYSTEM, previous_object()); - target->eventDestruct(); - if( target ) { - destruct(target); - } - } - return 1; - } - if( archp(who) ) { - target = to_object(args); - } - if( !target && !(target = present(lower_case(args), who)) && - !(target = present(lower_case(args), environment(who))) ) { - return "No such thing."; - } - if( interactive(target) && !archp(who) ) { - return "You are not permitted to do that."; - } - msg = who->GetMessage("dest", target); - who->eventPrint("You dest " + target->GetShort() + ".", MSG_SYSTEM); - if( interactive(target) ) { - target->eventPrint(who->GetName() + " dests you.", MSG_SYSTEM); - } - environment(who)->eventPrint(msg, MSG_SYSTEM, ({ who, target })); - target->eventDestruct(); - if( target ) { - destruct(target); - } - return 1; - } - - string GetHelp() { - return ("Syntax: \n\n" - "This command destroys the object named. \"dest all\" " - "destroys all the items in your inventory. See \"help format\" " - "for how to denote objects.\n\n" - "See also: clean, scan"); - } --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/creators/domains.c ds2.1/lib/cmds/creators/domains.c *** ds1.1/lib/cmds/creators/domains.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/domains.c Wed Jul 5 00:01:03 2006 *************** *** 17,23 **** mapping stats = ([]); string array domains; mixed array tmp; ! foreach(string domain, mixed data in domain_stats()) { if( !data ) { continue; --- 17,23 ---- mapping stats = ([]); string array domains; mixed array tmp; ! foreach(string domain, mixed data in domain_stats()) { if( !data ) { continue; *************** *** 31,59 **** stats[domain] = data; } domains = sort_array(keys(stats), function(string a, string b, mapping mp) { ! if( mp[a]["moves"] > mp[b]["moves"] ) { ! return -1; ! } ! else { ! return 1; ! } ! }, stats); tmp = ({ sprintf("%:-15s %:-11s %:-11s %:-11s %:-11s %s", "Domain", ! "Moves", "Objects", "Errors", "Heart Beats", ! "Array Size"), sprintf("%'-'" + (width-1) + "s", "") }); foreach(string domain in domains) { tmp += ({ sprintf("%:-15s %:-11d %:-11d %:-11d %:-11d %d", ! capitalize(domain), stats[domain]["moves"], ! stats[domain]["objects"], stats[domain]["errors"], ! stats[domain]["heart_beats"], ! stats[domain]["array_size"]) }); } who->eventPage(tmp, MSG_SYSTEM); return 1; } ! string GetHelp() { return ("Syntax: \n\n" ! "Prints out domain statistics for the mud's domains.\n\n" ! "See also: realms"); } --- 31,59 ---- stats[domain] = data; } domains = sort_array(keys(stats), function(string a, string b, mapping mp) { ! if( mp[a]["moves"] > mp[b]["moves"] ) { ! return -1; ! } ! else { ! return 1; ! } ! }, stats); tmp = ({ sprintf("%:-15s %:-11s %:-11s %:-11s %:-11s %s", "Domain", ! "Moves", "Objects", "Errors", "Heart Beats", ! "Array Size"), sprintf("%'-'" + (width-1) + "s", "") }); foreach(string domain in domains) { tmp += ({ sprintf("%:-15s %:-11d %:-11d %:-11d %:-11d %d", ! capitalize(domain), stats[domain]["moves"], ! stats[domain]["objects"], stats[domain]["errors"], ! stats[domain]["heart_beats"], ! stats[domain]["array_size"]) }); } who->eventPage(tmp, MSG_SYSTEM); return 1; } ! string GetHelp() { return ("Syntax: \n\n" ! "Prints out domain statistics for the mud's domains.\n\n" ! "See also: realms"); } diff -c -r --new-file ds1.1/lib/cmds/creators/elog.c ds2.1/lib/cmds/creators/elog.c *** ds1.1/lib/cmds/creators/elog.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/elog.c Wed Jul 5 00:01:03 2006 *************** *** 9,15 **** inherit LIB_DAEMON; int cmd(string str) { ! if(!str) str = DIR_ERROR_LOGS+"/"+(string)previous_object()->GetKeyName(); else str = DIR_ERROR_LOGS+"/"+str; write(str+":\n"); if(!tail(str)) write("No errors in "+str+".\nTry /log/debug.log.\n"); --- 9,15 ---- inherit LIB_DAEMON; int cmd(string str) { ! if(!str) str = DIR_ERROR_LOGS+"/"+(string)previous_object()->GetKeyName(); else str = DIR_ERROR_LOGS+"/"+str; write(str+":\n"); if(!tail(str)) write("No errors in "+str+".\nTry /log/debug.log.\n"); diff -c -r --new-file ds1.1/lib/cmds/creators/events.c ds2.1/lib/cmds/creators/events.c *** ds1.1/lib/cmds/creators/events.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/events.c Wed Jul 5 00:01:03 2006 *************** *** 15,21 **** string *obs; string *st2; string st3; ! int i,j,k; string name; if(!str && archp(previous_object())) { --- 15,21 ---- string *obs; string *st2; string st3; ! int i,j,k,l; string name; if(!str && archp(previous_object())) { *************** *** 23,31 **** i = sizeof(obs = keys(mp)); message("info", "The following events are pending:", this_player()); while(i--) { ! message("info", arrange_string(obs[i], 30) + ! arrange_string(mp[obs[i]]["function"], 15) + ! ctime(mp[obs[i]]["time"])+" Mud Time", this_player()); } return 1; } else if((archp(previous_object()) && str) || creatorp(previous_object())) { --- 23,32 ---- i = sizeof(obs = keys(mp)); message("info", "The following events are pending:", this_player()); while(i--) { ! l=atoi(""+obs[i]); ! message("info", arrange_string(""+l, 30) + ! arrange_string(mp[obs[i]]["function"], 15) + ! local_ctime(l)+" "+query_tz(), this_player()); } return 1; } else if((archp(previous_object()) && str) || creatorp(previous_object())) { *************** *** 38,44 **** i = sizeof(obs = keys(mp)); if (i) { while(i--) ! if((st2 = explode(obs[i], "/"))) if (st2[0] == "realms" && st2[1] == name) { if (j == 0) { if (archp(previous_object())) --- 39,45 ---- i = sizeof(obs = keys(mp)); if (i) { while(i--) ! if((st2 = explode(""+obs[i], "/"))) if (st2[0] == "realms" && st2[1] == name) { if (j == 0) { if (archp(previous_object())) *************** *** 51,57 **** for (k = 2; k < sizeof(st2); k++) st3 += "/" + st2[k]; message("info", arrange_string(st3, 30) + ! arrange_string(mp[obs[i]]["function"], 15) + ctime(mp[obs[i]]["time"])+" Mud Time", this_player()); } } --- 52,58 ---- for (k = 2; k < sizeof(st2); k++) st3 += "/" + st2[k]; message("info", arrange_string(st3, 30) + ! arrange_string(mp[obs[i]]["function"], 15) + ctime(mp[obs[i]]["time"])+" Mud Time", this_player()); } } diff -c -r --new-file ds1.1/lib/cmds/creators/exits.c ds2.1/lib/cmds/creators/exits.c *** ds1.1/lib/cmds/creators/exits.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/exits.c Wed Jul 5 00:01:03 2006 *************** *** 15,21 **** object oEnv; if ( !( oEnv = environment( this_player() ) ) ) ! return "You do not have a valid environment."; asExits = oEnv->GetExits(); asEnters = oEnv->GetEnters(); --- 15,21 ---- object oEnv; if ( !( oEnv = environment( this_player() ) ) ) ! return "You do not have a valid environment."; asExits = oEnv->GetExits(); asEnters = oEnv->GetEnters(); *************** *** 24,48 **** this_player() ); if ( !( sizeof( asExits ) ) ) ! message( "my_action", "This room has no exits.", this_player() ); else { ! message( "Nmy_action", "This room has the following exits :\n\n", ! this_player() ); ! foreach( sExit in asExits ) { ! message( "my_action", sprintf( "\t%10s -> %s", sExit, ! oEnv->GetExit( sExit ) ), this_player() ); ! } } if ( !( sizeof( asEnters ) ) ) ! message( "my_action", "\nThis room has no enters.", this_player() ); else { ! message( "Nmy_action", "\nThis room has the following enters :\n\n", ! this_player() ); ! foreach( sExit in asEnters ) { ! message( "my_action", sprintf( "\t%10s -> %s", sExit, ! oEnv->GetEnter( sExit ) ), this_player() ); ! } } return 1; --- 24,48 ---- this_player() ); if ( !( sizeof( asExits ) ) ) ! message( "my_action", "This room has no exits.", this_player() ); else { ! message( "Nmy_action", "This room has the following exits :\n\n", ! this_player() ); ! foreach( sExit in asExits ) { ! message( "my_action", sprintf( "\t%10s -> %s", sExit, ! oEnv->GetExit( sExit ) ), this_player() ); ! } } if ( !( sizeof( asEnters ) ) ) ! message( "my_action", "\nThis room has no enters.", this_player() ); else { ! message( "Nmy_action", "\nThis room has the following enters :\n\n", ! this_player() ); ! foreach( sExit in asEnters ) { ! message( "my_action", sprintf( "\t%10s -> %s", sExit, ! oEnv->GetEnter( sExit ) ), this_player() ); ! } } return 1; diff -c -r --new-file ds1.1/lib/cmds/creators/expel.c ds2.1/lib/cmds/creators/expel.c *** ds1.1/lib/cmds/creators/expel.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/expel.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,53 ---- + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string args) { + object ob, *obs; + + if( !args || args == "" ) return "Expel whom?"; + ob = present(args,environment(this_player())); + if(args != "all" && (!ob || !living(ob))){ + + return "Expel only works for living things in your environment."; + } + if(archp(ob) && !archp(this_player())){ + write("You can't expel an admin."); + tell_player(ob, this_player()->GetName()+" just tried to expel you."); + return 1; + } + + if(args == "all"){ + if(archp(this_player())) { + obs = filter(get_livings(environment(this_player())), (: $1 != this_player() :) ); + } + else { + obs = filter(get_livings(environment(this_player())), + (: $1 != this_player() && !archp($1) :) ); + } + } + + else obs = ({ ob }); + + foreach(object nuisance in obs){ + nuisance->eventWimpy(1); + } + + foreach(object nuisance in obs){ + if(environment(nuisance) == environment(this_player())){ + if(creatorp(nuisance)) { + nuisance->eventMoveLiving(homedir(nuisance)+"/workroom"); + } + else nuisance->eventMoveLiving(ROOM_START); + } + } + + return 1; + } + + void help() { + message("help", "Syntax: expel \n\n" + "Forces the specified living thing to leave your environment.\n\n" + "See also: return, goto, move, trans", this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/findobj.c ds2.1/lib/cmds/creators/findobj.c *** ds1.1/lib/cmds/creators/findobj.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/findobj.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,46 ---- + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string args) { + string tmpfile; + string ret = ""; + object *obs; + + if(args) args = replace_string(args,"\"",""); + + if(!args) obs = ({ this_player() }); + + else obs = findobs(args); + + if(!sizeof(obs)) { + write("No such objects found."); + return 1; + } + + write(sizeof(obs)+" matches found. They are:\n\n"); + + foreach(object ob in obs){ + string name; + string str = "%^BOLD%^BLUE%^Object: "+identify(ob)+", "; + if(args != "door" && name = ob->GetName()) str += "%^BOLD%^GREEN%^name: "+name+", "; + str += "%^BOLD%^WHITE%^"; + if(environment(ob)) str += "environment: "+identify(environment(ob))+".\n"; + else str += "environment: None.\n"; + str += "%^RESET%^\n"; + ret += str; + } + + tmpfile = generate_tmp(); + write_file(tmpfile,ret); + this_player()->eventPage(tmpfile); + rm(tmpfile); + return 1; + } + + string GetHelp() { + return ("Syntax: findobj STRING\n\n" + "Displays matching objects that are loaded into memory.\n\n" + "examples: \n\nfindobj staff\nfindobj /lib/dummy"); + } diff -c -r --new-file ds1.1/lib/cmds/creators/force.c ds2.1/lib/cmds/creators/force.c *** ds1.1/lib/cmds/creators/force.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/force.c Wed Dec 31 19:00:00 1969 *************** *** 1,65 **** - /* /cmds/creators/force.c - * From the Dead Souls V Object Library - * Created by Descartes of Borg 961018 - * Version: %A% - * Last modified: %D% - */ - - #include - - inherit LIB_DAEMON; - - mixed cmd(string args) { - object who = previous_object(); - object target; - string name, cmd; - - if( sscanf(args, "%s to %s", name, cmd) != 1 ) { - int i = strsrch(args, " "); - - name = ""; - while( i != -1 ) { - name += args[0..(i-1)]; - if( strlen(args) < i-1 ) { - args = args[(i+1)..]; - } - else { - args = ""; - } - if( target = find_living(lower_case(name)) ) { - break; - } - if( target = find_living(convert_string(name)) ) { - break; - } - } - if( !target ) { - who->eventPrint("Cannot find any living thing called: " + name); - return 1; - } - cmd = args; - } - else { - target = find_living(lower_case(name)); - if( !target ) { - target = find_living(convert_string(name)); - } - if( !target ) { - who->eventPrint("Cannot find any living thing called: " + name); - return 1; - } - } - target->eventPrint(who->GetName() + " forces you to: " + cmd); - who->eventPrint("You force " + target->GetShort() + " to: " + cmd); - target->eventForce(cmd); - return 1; - } - - string GetErorMessage() { - "Force whom to do what?"; - } - - string GetHelp() { - return ("Syntax: \n\n" - "Allows you to force a living object to take a certain action."); - } --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/creators/format.c ds2.1/lib/cmds/creators/format.c *** ds1.1/lib/cmds/creators/format.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/format.c Wed Jul 5 00:01:03 2006 *************** *** 9,49 **** int cmd(string str) { ! write("This is a fake wiz command. Try \"help format\" to get" + ! " information on\nspecifying objects for certain wiz commands.\n"); ! return 1; } int help() { ! write("NOTE: This is not a command in itself.\n" + ! "Certain wizard commands require that you specify\n" + ! "objects in a certain format.\n" + ! "The format uses prefixes to specify types of\n" + ! "objects as follows:\n" + ! " !ob ob is NOT an NPC or player\n" + ! " %ob ob is a player\n" + ! " $ob ob is an NPC\n" + ! " #int int is an ordinal value, e.g. 0, 1 , 2...\n" + ! " /str str is a filename of an object\n" + ! "Objects can also be \"me\", which is your player\n" + ! " object, or \"here\", which is you environment.\n"); ! write("Objects denoted by prefixes are joined by a few\n" + ! "functional symbols:\n" + ! " object@environment denotes the object at an\n" + ! " environment. Environment can be either an\n" + ! " object or an object@environment.\n" + ! " e(object) denotes the environment of object.\n\n"); ! write("For example:\n" + ! " !sword@%descartes is the sword in Descartes'\n" + ! " inventory.\n" + ! " #2@!bag@$orc@here is the 3rd item in the bag\n" + ! " that the orc in front of you is holding.\n" + ! " NOTE: #0 is the first object.\n" + ! " $orc@/d/standard/square is the orc that\n" + ! " shouldn't be in the square.\n" + ! "See also: patch\n"+ ! "See man: to_object, get_object, get_objects\n"+ ! ""); ! return 1; } --- 9,49 ---- int cmd(string str) { ! write("This is a fake wiz command. Try \"help format\" to get" + ! " information on\nspecifying objects for certain wiz commands.\n"); ! return 1; } int help() { ! write("NOTE: This is not a command in itself.\n" + ! "Certain wizard commands require that you specify\n" + ! "objects in a certain format.\n" + ! "The format uses prefixes to specify types of\n" + ! "objects as follows:\n" + ! " !ob ob is NOT an NPC or player\n" + ! " %ob ob is a player\n" + ! " $ob ob is an NPC\n" + ! " #int int is an ordinal value, e.g. 0, 1 , 2...\n" + ! " /str str is a filename of an object\n" + ! "Objects can also be \"me\", which is your player\n" + ! " object, or \"here\", which is you environment.\n"); ! write("Objects denoted by prefixes are joined by a few\n" + ! "functional symbols:\n" + ! " object@environment denotes the object at an\n" + ! " environment. Environment can be either an\n" + ! " object or an object@environment.\n" + ! " e(object) denotes the environment of object.\n\n"); ! write("For example:\n" + ! " !sword@%descartes is the sword in Descartes'\n" + ! " inventory.\n" + ! " #2@!bag@$orc@here is the 3rd item in the bag\n" + ! " that the orc in front of you is holding.\n" + ! " NOTE: #0 is the first object.\n" + ! " $orc@/d/standard/square is the orc that\n" + ! " shouldn't be in the square.\n" + ! "See also: patch\n"+ ! "See man: to_object, get_object, get_objects\n"+ ! ""); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/creators/goto.c ds2.1/lib/cmds/creators/goto.c *** ds1.1/lib/cmds/creators/goto.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/goto.c Wed Jul 5 00:01:03 2006 *************** *** 8,32 **** #include inherit LIB_DAEMON; ! mixed cmd(string str) { object ob; if(!str) return "Goto where?"; if((ob = find_living(lower_case(str))) && (!ob->GetInvis() || !archp(ob)) && ob=environment(ob)) { ! if(ob == environment(this_player())) { ! message("my_action", "You twitch.", this_player()); ! if(hiddenp(this_player())) return 1; ! message("other_action", (string)this_player()->GetName()+ ! " twitches.", ob, ({ this_player() })); ! return 1; ! } } if(ob && ob->GetInvis() && creatorp(ob) && !archp(this_player())) ob = 0; if(!ob) str = absolute_path((string)this_player()->query_cwd(), str); ! if(ob) this_player()->eventMoveLiving(ob, ""); ! else this_player()->eventMoveLiving(str, ""); return 1; } --- 8,40 ---- #include inherit LIB_DAEMON; ! mixed cmd(string str) { object ob; if(!str) return "Goto where?"; if((ob = find_living(lower_case(str))) && (!ob->GetInvis() || !archp(ob)) && ob=environment(ob)) { ! if(ob == environment(this_player())) { ! message("my_action", "You twitch.", this_player()); ! if(hiddenp(this_player())) return 1; ! message("other_action", (string)this_player()->GetName()+ ! " twitches.", ob, ({ this_player() })); ! return 1; ! } } if(ob && ob->GetInvis() && creatorp(ob) && !archp(this_player())) ob = 0; if(!ob) str = absolute_path((string)this_player()->query_cwd(), str); ! if(ob) { ! this_player()->eventMoveLiving(ob, ""); ! return 1; ! } ! if(!file_exists(str)) str += ".c"; ! if(!file_exists(str)) { ! write("Location not found."); ! return 1; ! } ! else this_player()->eventMoveLiving(str, ""); return 1; } *************** *** 35,41 **** "Syntax: \n\n" "This command will move you to where the living thing is if it can " "be found, otherwise it will search for the file named and try to " ! "move you into that file.\n\nSee also: home, move, trans.", this_player() ); } --- 43,49 ---- "Syntax: \n\n" "This command will move you to where the living thing is if it can " "be found, otherwise it will search for the file named and try to " ! "move you into that file.\n\nSee also: home, move, trans, expel.", this_player() ); } diff -c -r --new-file ds1.1/lib/cmds/creators/home.c ds2.1/lib/cmds/creators/home.c *** ds1.1/lib/cmds/creators/home.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/home.c Wed Jul 5 00:01:03 2006 *************** *** 19,76 **** else who = lower_case(str); str = user_path(who); if( ob = (object)this_player()->query_property("workroom") ) { ! if(ob == prev) return "You twitch."; ! if( (int)this_player()->eventMove(ob) ) { ! this_player()->eventDescribeEnvironment(0); ! if(hiddenp(this_player()) || this_player()->GetInvis()) ! return 1; ! message("mmout", (string)this_player()->GetMessage("home"), prev); ! message("mmin", (string)this_player()->GetMessage("telin"), ob, ! ({ this_player() })); ! return 1; ! } } if( !ob ) { ! if( !(ob = load_object(str+"workroom")) && ! str == user_path((string)this_player()->GetKeyName())) { ! ob = new(DIR_OBJ + "workroom"); ! this_player()->set_property("workroom", ob); ! } ! else if( !(ob = load_object(str+"workroom")) ) { ! if(!(ob = find_player(who)) || !(ob=(object)ob->query_property("workroom"))) ! return capitalize(who)+" has no active workroom."; ! } ! else { ! if( file_name(prev) == str+"workroom" ) ! return "You twitch."; ! if( (int)this_player()->eventMove(ob) ) { ! this_player()->eventDescribeEnvironment(0); ! if(hiddenp(this_player()) || this_player()->GetInvis()) ! return 1; ! message("mmout", (string)this_player()->GetMessage("home"), prev); ! message("mmin", (string)this_player()->GetMessage("telin"), ! environment(this_player()), ({ this_player() })); ! return 1; ! } ! return "You stay where you are."; ! } } if(ob == prev) return "You twitch."; if( (int)this_player()->eventMove(ob) ) { ! this_player()->eventDescribeEnvironment(0); ! if(hiddenp(this_player()) || this_player()->GetInvis()) return 1; ! message("mmout", (string)this_player()->GetMessage("home"), prev); ! message("mmin",(string)this_player()->GetMessage("telin"),ob,({this_player()})); ! return 1; } return "You stay where you are."; } void help() { message("help", "Syntax: \n \n\n" ! "Without arguments, this command will take you to your workroom. " ! "With arguments, it takes you to the workroom of the person " ! "you specify.\n\n" ! "See also: goto, trans", this_player()); } --- 19,76 ---- else who = lower_case(str); str = user_path(who); if( ob = (object)this_player()->query_property("workroom") ) { ! if(ob == prev) return "You twitch."; ! if( (int)this_player()->eventMove(ob) ) { ! this_player()->eventDescribeEnvironment(0); ! if(hiddenp(this_player()) || this_player()->GetInvis()) ! return 1; ! message("mmout", (string)this_player()->GetMessage("home"), prev); ! message("mmin", (string)this_player()->GetMessage("telin"), ob, ! ({ this_player() })); ! return 1; ! } } if( !ob ) { ! if( !(ob = load_object(str+"workroom")) && ! str == user_path((string)this_player()->GetKeyName())) { ! ob = new(DIR_OBJ + "workroom"); ! this_player()->set_property("workroom", ob); ! } ! else if( !(ob = load_object(str+"workroom")) ) { ! if(!(ob = find_player(who)) || !(ob=(object)ob->query_property("workroom"))) ! return capitalize(who)+" has no active workroom."; ! } ! else { ! if( file_name(prev) == str+"workroom" ) ! return "You twitch."; ! if( (int)this_player()->eventMove(ob) ) { ! this_player()->eventDescribeEnvironment(0); ! if(hiddenp(this_player()) || this_player()->GetInvis()) ! return 1; ! message("mmout", (string)this_player()->GetMessage("home"), prev); ! message("mmin", (string)this_player()->GetMessage("telin"), ! environment(this_player()), ({ this_player() })); ! return 1; ! } ! return "You stay where you are."; ! } } if(ob == prev) return "You twitch."; if( (int)this_player()->eventMove(ob) ) { ! this_player()->eventDescribeEnvironment(0); ! if(hiddenp(this_player()) || this_player()->GetInvis()) return 1; ! message("mmout", (string)this_player()->GetMessage("home"), prev); ! message("mmin",(string)this_player()->GetMessage("telin"),ob,({this_player()})); ! return 1; } return "You stay where you are."; } void help() { message("help", "Syntax: \n \n\n" ! "Without arguments, this command will take you to your workroom. " ! "With arguments, it takes you to the workroom of the person " ! "you specify.\n\n" ! "See also: goto, trans", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/creators/i3who.c ds2.1/lib/cmds/creators/i3who.c *** ds1.1/lib/cmds/creators/i3who.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/i3who.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,18 ---- + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + foreach(string mud in INTERMUD_D->GetMuds()){ + SERVICES_D->eventSendWhoRequest(mud); + } + return 1; + } + + + void help() { + message("help", "Syntax: i3who\n\n" + "Queries each active mud for rwho information.\n\n", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/invis.c ds2.1/lib/cmds/creators/invis.c *** ds1.1/lib/cmds/creators/invis.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/invis.c Wed Jul 5 00:01:03 2006 *************** *** 8,20 **** varargs int cmd(string str) { ! if((int)this_player()->GetInvis()) { notify_fail("You are already invisible.\n"); return 0; } this_player()->SetInvis(1); message("my_action", "You fade into the shadows.", this_player()); ! return 1; } void help() --- 8,20 ---- varargs int cmd(string str) { ! if((int)this_player()->GetInvis()) { notify_fail("You are already invisible.\n"); return 0; } this_player()->SetInvis(1); message("my_action", "You fade into the shadows.", this_player()); ! return 1; } void help() diff -c -r --new-file ds1.1/lib/cmds/creators/last.c ds2.1/lib/cmds/creators/last.c *** ds1.1/lib/cmds/creators/last.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/last.c Wed Jul 5 00:01:03 2006 *************** *** 43,49 **** string GetHelp(string topic) { return ("Syntax: \n" ! " \n\n" ! "Gives you a list of the last bunch of people to login or logout " ! "from the enter log."); } --- 43,49 ---- string GetHelp(string topic) { return ("Syntax: \n" ! " \n\n" ! "Gives you a list of the last bunch of people to login or logout " ! "from the enter log."); } diff -c -r --new-file ds1.1/lib/cmds/creators/lightme.c ds2.1/lib/cmds/creators/lightme.c *** ds1.1/lib/cmds/creators/lightme.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/lightme.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,26 ---- + #include + + inherit LIB_COMMAND; + + int cmd(string str){ + int level; + if(!str){ + write("Your current radiant light is: "+this_player()->GetRadiantLight()+"."); + return 1; + } + if(sscanf(str,"%d",level) != 1){ + write("Please specify a numerical light level."); + return 1; + } + if(level < 0 || level > 100){ + write("Please enter a light level between 0 and 100"); + return 1; + } + this_player()->SetRadiantLight(level); + write("Your current radiant light is: "+this_player()->GetRadiantLight()+"."); + return 1; + } + + string GetHelp(string str){ + return "Reports or changes the amount of light your body radiates."; + } diff -c -r --new-file ds1.1/lib/cmds/creators/malloc.c ds2.1/lib/cmds/creators/malloc.c *** ds1.1/lib/cmds/creators/malloc.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/malloc.c Wed Jul 5 00:01:03 2006 *************** *** 5,23 **** int cmd(string arg) { ! malloc_status(); ! return 1; } int help() { ! write( @EndText Syntax: malloc Effect: Lists memory usage statistics Output will depend on memory management package specified in options.h when the driver is compiled. See man: malloc_status EndText ! ); ! return 1; } --- 5,23 ---- int cmd(string arg) { ! malloc_status(); ! return 1; } int help() { ! write( @EndText Syntax: malloc Effect: Lists memory usage statistics Output will depend on memory management package specified in options.h when the driver is compiled. See man: malloc_status EndText ! ); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/creators/man.c ds2.1/lib/cmds/creators/man.c *** ds1.1/lib/cmds/creators/man.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/man.c Wed Jul 5 00:01:03 2006 *************** *** 8,14 **** inherit LIB_DAEMON; ! #define MAN_PAGES ({ "sefun", "efun", "applies", "lfun" }) int cmd(string str) { string d, tmp; --- 8,14 ---- inherit LIB_DAEMON; ! #define MAN_PAGES ({ "sefun", "efun/all", "applies", "lfun" }) int cmd(string str) { string d, tmp; *************** *** 19,30 **** i = sizeof(MAN_PAGES); pages = ({}); while(i--) ! if(file_exists(tmp = sprintf("%s/%s/%s", DIR_DOCS, MAN_PAGES[i], ! str))) pages += ({ tmp }); if(!(i = sizeof(pages))) return notify_fail("No such man page.\n"); else if(i > 1) ! message("system", "Showing only the first of "+i+" man pages.", ! this_player()); this_player()->eventPage(pages[0]); return 1; ! } --- 19,30 ---- i = sizeof(MAN_PAGES); pages = ({}); while(i--) ! if(file_exists(tmp = sprintf("%s/%s/%s", DIR_DOCS, MAN_PAGES[i], ! str))) pages += ({ tmp }); if(!(i = sizeof(pages))) return notify_fail("No such man page.\n"); else if(i > 1) ! message("system", "Showing only the first of "+i+" man pages.", ! this_player()); this_player()->eventPage(pages[0]); return 1; ! } diff -c -r --new-file ds1.1/lib/cmds/creators/margins.c ds2.1/lib/cmds/creators/margins.c *** ds1.1/lib/cmds/creators/margins.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/margins.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,19 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + return @ENDTEXT + |---------------------------------------------------------------|-------------| + ENDTEXT; + } + + void help() { + write("Syntax: margins\n"); + write(@EndText + This simple command prints a line to help creators when writing + descriptions. It gives a visual indicator of when to stop on + one line and continue on the next. + EndText + ); + } diff -c -r --new-file ds1.1/lib/cmds/creators/message.c ds2.1/lib/cmds/creators/message.c *** ds1.1/lib/cmds/creators/message.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/message.c Wed Jul 5 00:01:03 2006 *************** *** 12,43 **** string type, msg; if( !args || args == "" ) { ! mapping msgs; ! string *cles; ! int i; ! string tmp = ""; ! ! i = sizeof(cles = keys(msgs = (mapping)this_player()->GetMessages())); ! while(i--) tmp += sprintf("%:-10s %s\n", cles[i], msgs[cles[i]]); ! message("system", tmp, this_player()); ! return 1; } if( sscanf(args, "%s %s", type, msg) != 2) return "Set it to what?"; if( !((int)this_player()->SetMessage(type, msg)) ) ! return "Invalid message type."; message("system", "Message " + type + " changed to:\n" + msg, ! this_player()); return 1; } void help() { message("help", "Syntax: \n\n" ! "Allows you to modify standard " + mud_name() + " messages. " ! "The message types are come, leave, telin, telout, home, " ! "clone, dest, login, logout, say, ask, exclaim. Not that " ! "with say, ask, and exclaim you only may enter in the verbs. " ! "Depending on the message class, you may place such placeholders " ! "as:\n$M\t" + mud_name() + "\n$N\tYour name\n$D\tdirection\n" ! "$O\tobject", ! this_player()); } --- 12,43 ---- string type, msg; if( !args || args == "" ) { ! mapping msgs; ! string *cles; ! int i; ! string tmp = ""; ! ! i = sizeof(cles = keys(msgs = (mapping)this_player()->GetMessages())); ! while(i--) tmp += sprintf("%:-10s %s\n", cles[i], msgs[cles[i]]); ! message("system", tmp, this_player()); ! return 1; } if( sscanf(args, "%s %s", type, msg) != 2) return "Set it to what?"; if( !((int)this_player()->SetMessage(type, msg)) ) ! return "Invalid message type."; message("system", "Message " + type + " changed to:\n" + msg, ! this_player()); return 1; } void help() { message("help", "Syntax: \n\n" ! "Allows you to modify standard " + mud_name() + " messages. " ! "The message types are come, leave, telin, telout, home, " ! "clone, dest, login, logout, say, ask, exclaim. Not that " ! "with say, ask, and exclaim you only may enter in the verbs. " ! "Depending on the message class, you may place such placeholders " ! "as:\n$M\t" + mud_name() + "\n$N\tYour name\n$D\tdirection\n" ! "$O\tobject", ! this_player()); } diff -c -r --new-file ds1.1/lib/cmds/creators/move.c ds2.1/lib/cmds/creators/move.c *** ds1.1/lib/cmds/creators/move.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/move.c Wed Dec 31 19:00:00 1969 *************** *** 1,55 **** - /* /cmds/creators/move.c - * From the Dead Souls V Object Library - * Moves object from one place to another - * created by Descartes of Borg 961008 - * Version: @(#) move.c 1.2@(#) - * Last modified: 96/10/08 - */ - - #include - #include - - inherit LIB_DAEMON; - - mixed cmd(string args) { - object what, destination; - string a, b; - mixed res; - - if( sscanf(args, "%s into %s", a, b) != 2 && - sscanf(args, "%s to %s", a, b) != 2 ) { - return "Syntax: \n\n"; - } - what = to_object(a); - destination = to_object(b); - if( !what ) { - return "Unable to find " + a + "."; - } - if( !destination ) { - return "Unable to find " + b + "."; - } - if( living(what) && living(destination) ) { - return "None of that nonsense."; - } - res = what->eventMove(destination); - if( !res ) { - return "Failed to move " + identify(what) + " into " + - identify(destination) + "."; - } - else if( res != 1 ) { - return res; - } - previous_object()->eventPrint("Moved " + identify(what) + " into " + - identify(destination) + ".", MSG_SYSTEM); - if( living(what) ) { - what->eventDescribeEnvironment(); - } - return 1; - } - - string GetHelp() { - return ("Syntax: \n\n" - "Allows you to move the object you name into the container " - "you name.\n\n" - "See also: trans"); - } --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/creators/mraces.c ds2.1/lib/cmds/creators/mraces.c *** ds1.1/lib/cmds/creators/mraces.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/mraces.c Wed Jul 5 00:01:03 2006 *************** *** 2,31 **** * A tool for cres which displays a listing of all preset npc races * Blitz@NM-IVD */ ! #include ! #include ! mixed cmd(string str) { ! string *types; ! if( str ) types = regexp(PresetNpcTypes, "^"+str); ! else types = PresetNpcTypes; ! if( !sizeof(types) ) { ! if( !str ) return "No list at this time."; ! return "No match was found for \""+str+"\"."; ! } ! types = sort_array(types, 1); ! message("help", format_page(types, 5), this_player() ); ! return 1; } ! void help() { ! message("info", ! "Syntax: mraces\n" ! " mraces \n\n" ! "A simple tool for creators which will list available 'preset' npc " ! "races. Entering \"mraces\" along will list all races. Entering " ! "\"mraces a\" will list all races that begin with 'a', etc.", ! this_player() ); } ! --- 2,28 ---- * A tool for cres which displays a listing of all preset npc races * Blitz@NM-IVD */ ! #include ! #include ! mixed cmd(string str) { ! string *types; ! ! types = load_object(RACES_D)->GetRaces(); ! if( !sizeof(types) ) { ! return "No list at this time."; ! } ! types = sort_array(types, 1); ! message("help", format_page(types, 5), this_player() ); ! return 1; } ! void help() { ! message("info", ! "Syntax: mraces\n" ! " mraces \n\n" ! "A simple tool for creators which will list available npc races.", ! this_player() ); } ! diff -c -r --new-file ds1.1/lib/cmds/creators/mstatus.c ds2.1/lib/cmds/creators/mstatus.c *** ds1.1/lib/cmds/creators/mstatus.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/mstatus.c Wed Jul 5 00:01:03 2006 *************** *** 9,15 **** } string GetHelp(string str) { ! return (@EndText Syntax: mstatus [] Effect: Give you statistics on the driver and mudlib If the optional argument is given, you also get: --- 9,15 ---- } string GetHelp(string str) { ! return (@EndText Syntax: mstatus [] Effect: Give you statistics on the driver and mudlib If the optional argument is given, you also get: diff -c -r --new-file ds1.1/lib/cmds/creators/netstat.c ds2.1/lib/cmds/creators/netstat.c *** ds1.1/lib/cmds/creators/netstat.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/netstat.c Wed Jul 5 00:01:03 2006 *************** *** 18,24 **** void help() { message("help", "Syntax: \n\n" ! "Gives you information about sockets being used by the LPC " ! "server through the MudOS socket efuns.\n\n" ! "See also: callouts, dumpallobj, mstatus", this_player()); } --- 18,24 ---- void help() { message("help", "Syntax: \n\n" ! "Gives you information about sockets being used by the LPC " ! "server through the MudOS socket efuns.\n\n" ! "See also: callouts, dumpallobj, mstatus", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/creators/notices.c ds2.1/lib/cmds/creators/notices.c *** ds1.1/lib/cmds/creators/notices.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/notices.c Wed Jul 5 00:01:03 2006 *************** *** 2,15 **** * from the Dead Souls V Mud Library * created by Blitz@Dead Souls 950115 */ ! #include #include ! #define OneDay (3600 * 24) ! string GetHelp(string foo); ! mixed cmd(string str) { string * words; object ob = this_player(); --- 2,15 ---- * from the Dead Souls V Mud Library * created by Blitz@Dead Souls 950115 */ ! #include #include ! #define OneDay (3600 * 24) ! string GetHelp(string foo); ! mixed cmd(string str) { string * words; object ob = this_player(); *************** *** 17,65 **** if( !sizeof(str) ) x = 1; else x = to_int(str); if( x < 1 ) { ! if( !archp(this_player()) ) return GetHelp(0); ! words = explode(str, " "); ! if( words[0] == "-d" ) { ! if( sizeof(words) < 2 ) return GetHelp(0); ! x = to_int(words[1]); ! if( x < 1 && words[1] != "0" ) ! return "Bad value ("+words[1]+")."; ! if( NOTIFY_D->eventRemoveNotice(x) ) ! ob->eventPrint("Notice number " + x + " has been erased."); ! else ob->eventPrint("Could not remove number " + x + "."); ! return 1; ! } ! else if( words[0] == "-p" && sizeof(words) > 1 ) { ! string file = words[1]; ! if( sizeof(words) > 2 ) x = to_int(words[2]); ! else x = 1; ! if( x < 1 ) return GetHelp(0); ! if( NOTIFY_D->eventWriteNotices(file, time() - (OneDay*x)) ) ! ob->eventPrint("Notices dumped to " + file + "."); ! else ob->eventPrint("No notices found, nothing done."); ! return 1; ! } ! else return GetHelp(0); } x = time() - (OneDay * x); if( !(int)NOTIFY_D->eventPrintNotices(this_player(), x) ) ! return "No recent notices found."; ! else return 1; } ! string GetHelp(string foo) { string str; str = "Syntax: notices\n" ! " notices \n\n" ! "Without arguments, this command displays all notices " ! "posted within the last 24 hours. You may also " ! "specify how many days back to search. For example, " ! "\"notices 7\" will display all notices posted within " ! "the last week.\n\n"; if( archp(this_player()) ) ! str += "Arch Commands: notices -d \n" ! " notices -p \n\n" ! "The d option deletes the specified notice id number.\n" ! "the p option will dump the output into \n"; return str; } --- 17,65 ---- if( !sizeof(str) ) x = 1; else x = to_int(str); if( x < 1 ) { ! if( !archp(this_player()) ) return GetHelp(0); ! words = explode(str, " "); ! if( words[0] == "-d" ) { ! if( sizeof(words) < 2 ) return GetHelp(0); ! x = to_int(words[1]); ! if( x < 1 && words[1] != "0" ) ! return "Bad value ("+words[1]+")."; ! if( NOTIFY_D->eventRemoveNotice(x) ) ! ob->eventPrint("Notice number " + x + " has been erased."); ! else ob->eventPrint("Could not remove number " + x + "."); ! return 1; ! } ! else if( words[0] == "-p" && sizeof(words) > 1 ) { ! string file = words[1]; ! if( sizeof(words) > 2 ) x = to_int(words[2]); ! else x = 1; ! if( x < 1 ) return GetHelp(0); ! if( NOTIFY_D->eventWriteNotices(file, time() - (OneDay*x)) ) ! ob->eventPrint("Notices dumped to " + file + "."); ! else ob->eventPrint("No notices found, nothing done."); ! return 1; ! } ! else return GetHelp(0); } x = time() - (OneDay * x); if( !(int)NOTIFY_D->eventPrintNotices(this_player(), x) ) ! return "No recent notices found."; ! else return 1; } ! string GetHelp(string foo) { string str; str = "Syntax: notices\n" ! " notices \n\n" ! "Without arguments, this command displays all notices " ! "posted within the last 24 hours. You may also " ! "specify how many days back to search. For example, " ! "\"notices 7\" will display all notices posted within " ! "the last week.\n\n"; if( archp(this_player()) ) ! str += "Arch Commands: notices -d \n" ! " notices -p \n\n" ! "The d option deletes the specified notice id number.\n" ! "the p option will dump the output into \n"; return str; } diff -c -r --new-file ds1.1/lib/cmds/creators/people.c ds2.1/lib/cmds/creators/people.c *** ds1.1/lib/cmds/creators/people.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/people.c Tue Jul 11 18:30:58 2006 *************** *** 15,24 **** static private string query_time(); private string calculateFormatString(int screenSize); int cmd(string str) { - object *who, *display; - string *args; string msg, tmp1, tmp2; int i, maxi, aflag, bflag, cflag, eflag, gflag, hflag, lflag, mflag; int nflag, pflag, rflag, sflag, uflag; --- 15,24 ---- static private string query_time(); private string calculateFormatString(int screenSize); + object *whom, *who, *display; + string *args; int cmd(string str) { string msg, tmp1, tmp2; int i, maxi, aflag, bflag, cflag, eflag, gflag, hflag, lflag, mflag; int nflag, pflag, rflag, sflag, uflag; *************** *** 26,74 **** string formatString; string bar; if(!str || str == "" || strlen(str) == 1 || str[0] != '-') args = ({}); else args = explode(str[1..strlen(str)-1], ""); i = sizeof(args); while(i--) { ! switch(args[i]) { ! case "a": aflag = 1; break; /* list arches */ ! case "b": bflag = 1; break; /* list ambassadors */ ! case "c": cflag = 1; break; /* list creators */ ! case "e": eflag = 1; break; /* sort by race */ ! case "g": gflag = 1; break; /* sort by age */ ! case "h": hflag = 1; break; /* list high mortals */ ! case "l": lflag = 1; break; /* sort by level */ ! case "m": mflag = 1; break; /* page through eventPage */ ! case "n": nflag = 1; break; /* list newbies */ ! case "p": pflag = 1; break; /* list regular mortals */ ! case "r": rflag = 1; break; /* sort by realm location */ ! case "s": sflag = 1; break; /* sort by class */ ! case "u": uflag = 1; break; /* list undead */ ! } } who = filter(users(), "filter_invis", this_object()); if(!aflag && !bflag && !cflag && !hflag && !nflag && !pflag && !uflag) ! display = who; else { ! display = ({}); ! if(aflag) display += filter(who, "filter_arches", this_object()); ! if(bflag) display += filter(who, "filter_ambass", this_object()); ! if(cflag) display += filter(who, "filter_cres", this_object()); ! if(hflag) display += filter(who, "filter_hms", this_object()); ! if(nflag) display += filter(who, "filter_newbie", this_object()); ! if(pflag) display += filter(who, "filter_mortal", this_object()); ! if(uflag) display += filter(who, "filter_undead", this_object()); ! display = distinct_array(display); } if(!eflag && !gflag && !lflag && !rflag && !sflag) ! maxi = sizeof(display=sort_array(display,"general_sort",this_object())); else { ! __SortFlags = ({ eflag, gflag, lflag, rflag, sflag }); ! maxi = sizeof(display = sort_array(display,"special_sort",this_object())); } screenSize = ((int*)this_player()->GetScreen())[0]; formatString = calculateFormatString(screenSize); - // 74 '-'s. bar = "--------------------------------------------------------------------------"; for(i = 75; i < screenSize; i++) bar += "-"; bar += "\n"; --- 26,81 ---- string formatString; string bar; + whom = ({}); + if(!str || str == "" || strlen(str) == 1 || str[0] != '-') args = ({}); else args = explode(str[1..strlen(str)-1], ""); i = sizeof(args); while(i--) { ! switch(args[i]) { ! case "a": aflag = 1; break; /* list arches */ ! case "b": bflag = 1; break; /* list ambassadors */ ! case "c": cflag = 1; break; /* list creators */ ! case "e": eflag = 1; break; /* sort by race */ ! case "g": gflag = 1; break; /* sort by age */ ! case "h": hflag = 1; break; /* list high mortals */ ! case "l": lflag = 1; break; /* sort by level */ ! case "m": mflag = 1; break; /* page through eventPage */ ! case "n": nflag = 1; break; /* list newbies */ ! case "p": pflag = 1; break; /* list regular mortals */ ! case "r": rflag = 1; break; /* sort by realm location */ ! case "s": sflag = 1; break; /* sort by class */ ! case "u": uflag = 1; break; /* list undead */ ! } } who = filter(users(), "filter_invis", this_object()); + foreach(object real_person in who){ + if(sizeof(base_name(real_person))) whom += ({ real_person }); + } + + who = whom; + if(!aflag && !bflag && !cflag && !hflag && !nflag && !pflag && !uflag) ! display = who; else { ! display = ({}); ! if(aflag) display += filter(who, "filter_arches", this_object()); ! if(bflag) display += filter(who, "filter_ambass", this_object()); ! if(cflag) display += filter(who, "filter_cres", this_object()); ! if(hflag) display += filter(who, "filter_hms", this_object()); ! if(nflag) display += filter(who, "filter_newbie", this_object()); ! if(pflag) display += filter(who, "filter_mortal", this_object()); ! if(uflag) display += filter(who, "filter_undead", this_object()); ! display = distinct_array(display); } if(!eflag && !gflag && !lflag && !rflag && !sflag) ! maxi = sizeof(display=sort_array(display,"general_sort",this_object())); else { ! __SortFlags = ({ eflag, gflag, lflag, rflag, sflag }); ! maxi = sizeof(display = sort_array(display,"special_sort",this_object())); } screenSize = ((int*)this_player()->GetScreen())[0]; formatString = calculateFormatString(screenSize); bar = "--------------------------------------------------------------------------"; for(i = 75; i < screenSize; i++) bar += "-"; bar += "\n"; *************** *** 89,94 **** --- 96,102 ---- } static int filter_invis(object ob) { + if(!ob || !sizeof(base_name(ob))) return 0; if(!((int)ob->GetKeyName())) return 0; if(!((int)ob->GetInvis(this_player()))) return 1; if(archp(this_player())) return 1; *************** *** 106,112 **** static int filter_newbie(object ob) { return (!creatorp(ob) && !ambassadorp(ob) && (MAX_NEWBIE_LEVEL >= ! (int)ob->GetLevel())); } static int filter_mortal(object ob) { --- 114,120 ---- static int filter_newbie(object ob) { return (!creatorp(ob) && !ambassadorp(ob) && (MAX_NEWBIE_LEVEL >= ! (int)ob->GetLevel())); } static int filter_mortal(object ob) { *************** *** 121,148 **** int x, y; if(archp(alpha)) { ! if(!archp(beta)) return -1; ! else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } else if(archp(beta)) return 1; if(creatorp(alpha)) { ! if(!creatorp(beta)) return -1; ! else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } else if(creatorp(beta)) return 1; if(ambassadorp(alpha)) { ! if(!ambassadorp(beta)) return -1; ! else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } else if(ambassadorp(beta)) return 1; if((x = (int)alpha->GetLevel()) > (y = (int)beta->GetLevel())) ! return -1; else if(x < y) return 1; else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } static int special_sort(object alpha, object beta) { --- 129,156 ---- int x, y; if(archp(alpha)) { ! if(!archp(beta)) return -1; ! else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } else if(archp(beta)) return 1; if(creatorp(alpha)) { ! if(!creatorp(beta)) return -1; ! else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } else if(creatorp(beta)) return 1; if(ambassadorp(alpha)) { ! if(!ambassadorp(beta)) return -1; ! else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } else if(ambassadorp(beta)) return 1; if((x = (int)alpha->GetLevel()) > (y = (int)beta->GetLevel())) ! return -1; else if(x < y) return 1; else return strcmp((string)alpha->GetCapName(), ! (string)beta->GetCapName()); } static int special_sort(object alpha, object beta) { *************** *** 150,197 **** int x, y; if(__SortFlags[4]) { ! if((a=(string)alpha->query_class())!=(b=(string)beta->query_class())) { ! if(!a) a = "zzzz"; ! if(!b) b= "zzzz"; ! return strcmp(a, b); ! } } if(__SortFlags[0]) { ! if((a=(string)alpha->query_race()) != (b=(string)beta->query_race())) { ! if(!a) a = "zzzz"; ! if(!b) b = "zzzz"; ! return strcmp(a, b); ! } } if(__SortFlags[3]) { ! if((a = file_name(environment(alpha))) != ! (b = file_name(environment(beta)))) return strcmp(a, b); } if(__SortFlags[2]) { ! if((x = (int)alpha->GetLevel()) != (y=(int)beta->GetLevel())) { ! if(x > y) return -1; ! else return 1; ! } } if(__SortFlags[1]) { ! if((x = (int)alpha->GetAge()) != (y = (int)beta->GetAge())) { ! if(x > y) return -1; ! else return 1; ! } } return 0; } private string calculateFormatString(int screenSize) { ! int nomSize = (((screenSize - 21) * 12) / 54); ! int ipSize = (((screenSize - 21) * 18) / 54); ! int envSize = (((screenSize - 21) * 24) / 54); ! ! if(nomSize < 12) nomSize = 12; ! if(ipSize < 18) ipSize = 18; ! if(envSize < 24) envSize = 24; ! ! return "%:-5s %:-2s %:-" + nomSize + "s %:-" + ipSize + "s %:-5s %:-3s %:-" + envSize + "s"; } --- 158,205 ---- int x, y; if(__SortFlags[4]) { ! if((a=(string)alpha->query_class())!=(b=(string)beta->query_class())) { ! if(!a) a = "zzzz"; ! if(!b) b= "zzzz"; ! return strcmp(a, b); ! } } if(__SortFlags[0]) { ! if((a=(string)alpha->query_race()) != (b=(string)beta->query_race())) { ! if(!a) a = "zzzz"; ! if(!b) b = "zzzz"; ! return strcmp(a, b); ! } } if(__SortFlags[3]) { ! if((a = file_name(environment(alpha))) != ! (b = file_name(environment(beta)))) return strcmp(a, b); } if(__SortFlags[2]) { ! if((x = (int)alpha->GetLevel()) != (y=(int)beta->GetLevel())) { ! if(x > y) return -1; ! else return 1; ! } } if(__SortFlags[1]) { ! if((x = (int)alpha->GetAge()) != (y = (int)beta->GetAge())) { ! if(x > y) return -1; ! else return 1; ! } } return 0; } private string calculateFormatString(int screenSize) { ! int nomSize = (((screenSize - 21) * 12) / 54); ! int ipSize = (((screenSize - 21) * 18) / 54); ! int envSize = (((screenSize - 21) * 24) / 54); ! ! if(nomSize < 12) nomSize = 12; ! if(ipSize < 18) ipSize = 18; ! if(envSize < 24) envSize = 24; ! ! return "%:-5s %:-2s %:-" + nomSize + "s %:-" + ipSize + "s %:-5s %:-3s %:-" + envSize + "s"; } *************** *** 207,219 **** if((int)ob->GetInvis()) nom = "("+nom+")"; if(in_edit(ob) || in_input(ob)) nom = "["+nom+"]"; if(creatorp(ob)) { ! if((int)ob->GetBlocked("all")) blk = "ACG"; ! else { ! if((int)ob->GetBlocked("cre")) blk = " C"; ! else blk = " "; ! if((int)ob->GetBlocked("gossip")) blk += "G"; ! else blk += " "; ! } } else blk = " "; if(!(x = (int)ob->GetLevel())) lev = "-"; --- 215,227 ---- if((int)ob->GetInvis()) nom = "("+nom+")"; if(in_edit(ob) || in_input(ob)) nom = "["+nom+"]"; if(creatorp(ob)) { ! if((int)ob->GetBlocked("all")) blk = "ACG"; ! else { ! if((int)ob->GetBlocked("cre")) blk = " C"; ! else blk = " "; ! if((int)ob->GetBlocked("gossip")) blk += "G"; ! else blk += " "; ! } } else blk = " "; if(!(x = (int)ob->GetLevel())) lev = "-"; *************** *** 225,245 **** if(!environment(ob)) env = "no environment"; else env = file_name(environment(ob)); if(!strsrch(env, REALMS_DIRS)) ! env = "~" + env[strlen(REALMS_DIRS)+1..]; else if(!strsrch(env, DOMAINS_DIRS)) ! env = "^"+env[strlen(DOMAINS_DIRS)+1..strlen(env)-1]; return sprintf(formatString, age, lev, nom, ip, idle, blk, env); } static private string query_time() { string tzone; ! int x; ! tzone = (string)this_player()->GetTimeZone() || localtime(time())[LT_ZONE]; ! x = (int)TIME_D->GetOffset(tzone) * 3600; return tzone + " time is: " + ctime(time() + x); } ! void help() { message("help", "Syntax: people [-abceghlmnprsu]\n\n" "Gives you a listing of people on "+mud_name()+". Output is " --- 233,256 ---- if(!environment(ob)) env = "no environment"; else env = file_name(environment(ob)); if(!strsrch(env, REALMS_DIRS)) ! env = "~" + env[strlen(REALMS_DIRS)+1..]; else if(!strsrch(env, DOMAINS_DIRS)) ! env = "^"+env[strlen(DOMAINS_DIRS)+1..strlen(env)-1]; return sprintf(formatString, age, lev, nom, ip, idle, blk, env); } static private string query_time() { string tzone; ! int x, offset; ! tzone = query_tz(); ! offset = (int)TIME_D->GetOffset(tzone); ! offset += EXTRA_TIME_OFFSET; ! if(query_os_type() != "windows" ) x = offset * 3600; ! else x = 0; return tzone + " time is: " + ctime(time() + x); } ! void help() { message("help", "Syntax: people [-abceghlmnprsu]\n\n" "Gives you a listing of people on "+mud_name()+". Output is " diff -c -r --new-file ds1.1/lib/cmds/creators/ping.c ds2.1/lib/cmds/creators/ping.c *** ds1.1/lib/cmds/creators/ping.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/ping.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,25 ---- + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + string target; + if(!str || str == "") str = "Dead Souls"; + target = INTERMUD_D->GetMudName(str); + this_player()->SetProperty("pinging",1); + INTERMUD_D->eventWrite(({ "auth-mud-req", 5, mud_name(), 0,target, 0 })); + + return 1; + } + + void help() { + message("help", "Syntax: ping \n\n" + "Pings a mud to test connectivity. Only pings to " + "Dead Souls muds are supported and recommended.\n" + "Note that you may receive a reply from a different " + "mud than the one specified if someone else already " + "initiated a ping, or if your mud's keepalive happens " + "to be running at the moment of your command.\n\n", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/polyglottize.c ds2.1/lib/cmds/creators/polyglottize.c *** ds1.1/lib/cmds/creators/polyglottize.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/polyglottize.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,41 ---- + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + object target; + + if(!str || str == "") str = "me"; + + if(str == "me") str = this_player()->GetKeyName(); + if(!target = present(str, environment(this_player()))){ + write("They're not here."); + return 1; + } + if(!living(target)) { + write("That's not a living thing."); + return 1; + } + if(creatorp(target) && !archp(this_player()) && + target != this_player()){ + write("That's impolite."); + tell_player(target,capitalize(this_player()->GetKeyName())+ + " just tried to polyglottize you."); + return 1; + } + + target->SetPolyglot(1); + if(target == this_player()) str = "yourself"; + else str = capitalize(str); + write("You polyglottize "+str+"."); + if(target != this_player()) + tell_object(target, capitalize(this_player()->GetKeyName())+" polyglottizes you."); + return 1; + } + + void help() { + message("help", "Syntax: polyglottize \n\n" + "Make the target able to understand all languages.\n\n", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/quell.c ds2.1/lib/cmds/creators/quell.c *** ds1.1/lib/cmds/creators/quell.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/quell.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,27 ---- + // By Magnafix 10-14-96 + // required addition of list_new_posts() in bboard daemon + #include + #include + + inherit LIB_COMMAND; + + + int cmd(string str){ + write("You casually wave your hand, and bring about peace."); + say(this_player()->GetCapName()+" waves "+possessive()+" hand "+ + "and brings peace to the area."); + foreach(object combatant in get_livings(environment(this_player()))){ + if(combatant->GetInCombat()) tell_object(combatant,"You stop fighting."); + combatant->eventQuell(); + } + + return 1; + } + + + + string GetHelp(string str) { + return "Syntax: \n" + "This command brings peace between combatants in your environment.\n" + "See also: unquell\n"; + } diff -c -r --new-file ds1.1/lib/cmds/creators/realms.c ds2.1/lib/cmds/creators/realms.c *** ds1.1/lib/cmds/creators/realms.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/realms.c Wed Jul 5 00:01:03 2006 *************** *** 20,29 **** text += ({ "Creator Moves Size Errors Objs HBs" }); text += ({ "-----------------------------------------------------" }); foreach(string name in names) { ! mapping foo = Stats[name]; ! text += ({ sprintf("%-14s %-8d %-8d %-8d %-6d %d", name, ! foo["moves"], foo["array_size"], foo["errors"], ! foo["objects"], foo["heart_beats"]) }); } this_player()->eventPage(text); return 1; --- 20,29 ---- text += ({ "Creator Moves Size Errors Objs HBs" }); text += ({ "-----------------------------------------------------" }); foreach(string name in names) { ! mapping foo = Stats[name]; ! text += ({ sprintf("%-14s %-8d %-8d %-8d %-6d %d", name, ! foo["moves"], foo["array_size"], foo["errors"], ! foo["objects"], foo["heart_beats"]) }); } this_player()->eventPage(text); return 1; *************** *** 31,38 **** string GetHelp(string str) { return ("Syntax: \n\n" ! "A creator command that displays individual author " ! "statistics relative to the \"areas\" found within " ! "their directories.\n\n" ! "See also: man author_stats"); } --- 31,38 ---- string GetHelp(string str) { return ("Syntax: \n\n" ! "A creator command that displays individual author " ! "statistics relative to the \"areas\" found within " ! "their directories.\n\n" ! "See also: man author_stats"); } diff -c -r --new-file ds1.1/lib/cmds/creators/rehash.c ds2.1/lib/cmds/creators/rehash.c *** ds1.1/lib/cmds/creators/rehash.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/rehash.c Wed Jul 5 00:01:03 2006 *************** *** 2,27 **** * This allows creators to refresh command lookup tables * Blitz@NM-IVD */ ! #include #include ! inherit LIB_DAEMON; ! mixed cmd(string str) { ! if( !sizeof(str) ) return "Syntax: rehash \n"; ! if( file_size(str) != -2 ) ! return str+": Path not found."; ! CMD_D->eventRehash(str); ! message("system", str+": Rehashed.", this_player() ); ! return 1; } ! void help() { ! message("help", ! "Syntax: rehash \n\n" ! "This command allows creators to refresh the specified path's " ! "command parsing lookup tables.", ! this_player() ); } ! --- 2,27 ---- * This allows creators to refresh command lookup tables * Blitz@NM-IVD */ ! #include #include ! inherit LIB_DAEMON; ! mixed cmd(string str) { ! if( !sizeof(str) ) return "Syntax: rehash \n"; ! if( file_size(str) != -2 ) ! return str+": Path not found."; ! CMD_D->eventRehash(str); ! message("system", str+": Rehashed.", this_player() ); ! return 1; } ! void help() { ! message("help", ! "Syntax: rehash \n\n" ! "This command allows creators to refresh the specified path's " ! "command parsing lookup tables.", ! this_player() ); } ! diff -c -r --new-file ds1.1/lib/cmds/creators/replog.c ds2.1/lib/cmds/creators/replog.c *** ds1.1/lib/cmds/creators/replog.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/replog.c Wed Jul 5 00:01:03 2006 *************** *** 11,22 **** if(!str) str = (string)this_player()->GetKeyName(); str = "/log/reports/"+str; if(!file_exists(str)) { ! notify_fail("No such file: "+str+".\n"); ! return 0; } if(!tail(str)) { ! notify_fail("Failed to read file: "+str+".\n"); ! return 0; } return 1; } --- 11,22 ---- if(!str) str = (string)this_player()->GetKeyName(); str = "/log/reports/"+str; if(!file_exists(str)) { ! notify_fail("No such file: "+str+".\n"); ! return 0; } if(!tail(str)) { ! notify_fail("Failed to read file: "+str+".\n"); ! return 0; } return 1; } diff -c -r --new-file ds1.1/lib/cmds/creators/reset.c ds2.1/lib/cmds/creators/reset.c *** ds1.1/lib/cmds/creators/reset.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/reset.c Wed Jul 5 00:01:03 2006 *************** *** 26,31 **** void help() { write("Syntax: or or \n\n"+ ! "Resets the object named or the environment you are in if no object\n"+ ! "is named.\n"); } --- 26,31 ---- void help() { write("Syntax: or or \n\n"+ ! "Resets the object named or the environment you are in if no object\n"+ ! "is named.\n"); } diff -c -r --new-file ds1.1/lib/cmds/creators/return.c ds2.1/lib/cmds/creators/return.c *** ds1.1/lib/cmds/creators/return.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/return.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,50 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string args) { + object ob, room; + string last_loc; + + if( !args || args == "" ) { + if(!last_loc = this_player()->GetProperty("LastLocation")){ + write("You have nowhere to return to."); + return 1; + } + else if(!load_object(last_loc)){ + write("There is a problem with that location."); + write("You remain where you are."); + return 1; + } + else this_player()->eventMoveLiving(load_object(last_loc)); + return 1; + } + + if( !(ob = find_player(convert_name(args))) && !(ob = find_living(args)) ) + return "No such being exists anywhere presently."; + if( !room = load_object(ob->GetProperty("ReturnSite"))){ + write("That person has nowhere to return."); + return 1; + } + + if(room == environment(ob)){ + write("That person is already there."); + return 1; + } + + ob->SetProperty("ReturnSite",""); + if( !((int)ob->eventMoveLiving(room) )) + return "Failed to move " + (string)ob->GetCapName() + "."; + message("system", "You have been returned to your previous location by " + + (string)this_player()->GetName() + ".", ob); + message("system", "You return " + (string)ob->GetCapName() + + " to their previous location.", this_player()); + return 1; + } + + void help() { + message("help", "Syntax: \n\n" + "Sends someone back, after a trans.\n" + "With no arguments, sends you to your last location.\n\n" + "See also: goto", this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/scan.c ds2.1/lib/cmds/creators/scan.c *** ds1.1/lib/cmds/creators/scan.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/scan.c Wed Jul 5 00:01:03 2006 *************** *** 4,91 **** * created by Descartes of Borg 950516 * -fi flags added for Dead Souls by Blitz 951208 */ ! #include ! #define OPT_E (1 << 1) #define OPT_D (1 << 2) #define OPT_I (1 << 3) #define OPT_F (1 << 4) ! inherit LIB_DAEMON; ! string inventory(object ob, int level, int scan); ! mixed cmd(string args) { object *inv; object ob; string tmp; int scan, i, maxi; ! if( args == "" || !args ) { ! ob = this_player(); ! scan = 0; } else { ! while(args[0] == '-') { ! switch(args[1]) { ! case 'd': scan |= OPT_D; break; ! case 'e': scan |= OPT_E; break; ! case 'i': scan |= OPT_I; break; ! case 'f': scan |= OPT_F; break; ! } ! if( strlen(args) > 3 ) args = trim(args[2..]); ! else args = ""; ! } ! if( args != "" ) ob = to_object(args); ! if( !ob ) ob = this_player(); } if( scan & OPT_E ) ob = environment(ob); if( !ob ) return "No environment for requested object."; if( scan & OPT_D ) tmp = "Deep scanning " + identify(ob) + ":\n"; else tmp = "Scanning " + identify(ob) + ":\n"; for(i=0, maxi = sizeof(inv = all_inventory(ob)); ieventPage(explode(tmp, "\n"), "system"); return 1; } ! string inventory(object ob, int level, int scan) { object *inv; string ret; int i, maxi; ! for(i = 1, ret = ""; i <= level; i++) ret += "\t"; if( scan & OPT_I ) { ! string tmp; ! if( scan & OPT_F ) tmp = identify(ob) + "\n" + ret + " "; ! else tmp = ""; ! tmp += sprintf("(%s) - Mass: %d Value: %d Class: %d", ! capitalize((string)ob->GetKeyName()), ! (int)ob->GetMass(), (int)ob->GetValue(), ! (int)ob->GetClass() ); ! if( ob->GetWorn() ) tmp += " (worn)"; ! ret += tmp; } else ret += identify(ob); if( ( scan & OPT_D ) && ! ( maxi = sizeof(inv = all_inventory(ob))) ) ret += ":\n"; else ret += "\n"; if( !( scan & OPT_D ) ) return ret; for(i=0; i\n\n" ! "Scans the inventory of the object you name. If you do " ! "not specify an object, then it gives you your inventory. " ! "If you specify the -e option, the command does the " ! "environment of the object which is targeted. If the -d " ! "option is specified, then a deep scan is done. The -i " ! "option displays information about each object. The -f " ! "option forces filenames to be displayed (default).\n\n" ! "See also: inventory, stat"; } ! --- 4,91 ---- * created by Descartes of Borg 950516 * -fi flags added for Dead Souls by Blitz 951208 */ ! #include ! #define OPT_E (1 << 1) #define OPT_D (1 << 2) #define OPT_I (1 << 3) #define OPT_F (1 << 4) ! inherit LIB_DAEMON; ! string inventory(object ob, int level, int scan); ! mixed cmd(string args) { object *inv; object ob; string tmp; int scan, i, maxi; ! if( args == "" || !args ) { ! ob = this_player(); ! scan = 0; } else { ! while(args[0] == '-') { ! switch(args[1]) { ! case 'd': scan |= OPT_D; break; ! case 'e': scan |= OPT_E; break; ! case 'i': scan |= OPT_I; break; ! case 'f': scan |= OPT_F; break; ! } ! if( strlen(args) > 3 ) args = trim(args[2..]); ! else args = ""; ! } ! if( args != "" ) ob = to_object(args); ! if( !ob ) ob = this_player(); } if( scan & OPT_E ) ob = environment(ob); if( !ob ) return "No environment for requested object."; if( scan & OPT_D ) tmp = "Deep scanning " + identify(ob) + ":\n"; else tmp = "Scanning " + identify(ob) + ":\n"; for(i=0, maxi = sizeof(inv = all_inventory(ob)); ieventPage(explode(tmp, "\n"), "system"); return 1; } ! string inventory(object ob, int level, int scan) { object *inv; string ret; int i, maxi; ! for(i = 1, ret = ""; i <= level; i++) ret += "\t"; if( scan & OPT_I ) { ! string tmp; ! if( scan & OPT_F ) tmp = identify(ob) + "\n" + ret + " "; ! else tmp = ""; ! tmp += sprintf("(%s) - Mass: %d Value: %d Class: %d", ! capitalize((string)ob->GetKeyName()), ! (int)ob->GetMass(), (int)ob->GetValue(), ! intp((int)ob->GetClass()) ? (int)ob->GetClass() : 0 ); ! if( ob->GetWorn() ) tmp += " (worn)"; ! ret += tmp; } else ret += identify(ob); if( ( scan & OPT_D ) && ! ( maxi = sizeof(inv = all_inventory(ob))) ) ret += ":\n"; else ret += "\n"; if( !( scan & OPT_D ) ) return ret; for(i=0; i\n\n" ! "Scans the inventory of the object you name. If you do " ! "not specify an object, then it gives you your inventory. " ! "If you specify the -e option, the command does the " ! "environment of the object which is targeted. If the -d " ! "option is specified, then a deep scan is done. The -i " ! "option displays information about each object. The -f " ! "option forces filenames to be displayed (default).\n\n" ! "See also: inventory, stat"; } ! diff -c -r --new-file ds1.1/lib/cmds/creators/showtree.c ds2.1/lib/cmds/creators/showtree.c *** ds1.1/lib/cmds/creators/showtree.c Sun Feb 1 21:29:51 1998 --- ds2.1/lib/cmds/creators/showtree.c Wed Jul 5 00:01:03 2006 *************** *** 15,21 **** string func, file; if( !str || str == "" ) ! return "Syntax: or "; if( sscanf(str, "%s in %s", func, file) != 2 ) { if( sscanf(str, "%s %s", func, file) != 2 ) { func = 0; --- 15,21 ---- string func, file; if( !str || str == "" ) ! return "Syntax: or "; if( sscanf(str, "%s in %s", func, file) != 2 ) { if( sscanf(str, "%s %s", func, file) != 2 ) { func = 0; *************** *** 33,39 **** object ob; string str; int found; ! if( strlen(file) > 2 && file[<2..] == ".c" ) file = file[0..<3]; if( file[0] != '/' ) file = "/" + file; if( !(ob = load_object(file)) ) { --- 33,39 ---- object ob; string str; int found; ! if( strlen(file) > 2 && file[<2..] == ".c" ) file = file[0..<3]; if( file[0] != '/' ) file = "/" + file; if( !(ob = load_object(file)) ) { *************** *** 61,71 **** string GetHelp(string str) { return ("Syntax: \n" ! " \n\n" ! "In its first version, shows you the full inheritance " ! "tree for the named object. In its second form, it shows " ! "you all files in the inheritance tree which contain the " ! "function you name, specifically noting those objects which " ! "have definitions for the function.\n\n" ! "See also: help"); } --- 61,71 ---- string GetHelp(string str) { return ("Syntax: \n" ! " \n\n" ! "In its first version, shows you the full inheritance " ! "tree for the named object. In its second form, it shows " ! "you all files in the inheritance tree which contain the " ! "function you name, specifically noting those objects which " ! "have definitions for the function.\n\n" ! "See also: help"); } diff -c -r --new-file ds1.1/lib/cmds/creators/stargate.c ds2.1/lib/cmds/creators/stargate.c *** ds1.1/lib/cmds/creators/stargate.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/stargate.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,46 ---- + /** + * modification of code contributed by daelas + * started 2006-04-04 + */ + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str){ + mapping network; + + network = STARGATE_D->GetStargates(); + if (str){ + if (network[lower_case(str)]){ + write(str+" is part of the Stargate Network.\n"); + write(str+" data: "+identify(network[lower_case(str)])); + } + else { + write(str+" is not currently part of the Stargate Network.\n"); + } + return 1; + } + else { + write("These are the current Stargate locations in the Network:\n"); + if (!sizeof(network)){ + write("No locations found."); + return 1; + } + else { + string buf = ""; + string name; + write(implode(keys(network), ", ")); + } + } + return 1; + } + + void help() { + message("help", "Syntax: stargate \n\n" + "With an argument, this command will determine whether the argument " + "supplied is a valid stargate. If so, stargate data on that gate " + "is displayed. Without an argument, this command lists known valid " + "stargates.", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/creators/stat.c ds2.1/lib/cmds/creators/stat.c *** ds1.1/lib/cmds/creators/stat.c Sun Feb 1 21:29:50 1998 --- ds2.1/lib/cmds/creators/stat.c Wed Dec 31 19:00:00 1969 *************** *** 1,105 **** - /* /cmds/creator/stat.c - * from the Dead Souls LPC Library - * a command to view something's stats - * created by Descartes of Borg 950409 - */ - - #include - - inherit LIB_DAEMON; - - mixed cmd(string args) { - string *lines, *arr, *limbs; - object ob; - string tmp1, tmp2; - int i, x, y, cols; - - if( args == "" || !args ) return 0; - if( !(ob = present(args, environment(this_player()))) ) - if( !(ob = find_player(convert_name(args))) && - !(ob = find_living(lower_case(args))) ) - return capitalize(args) + " is nowhere to be found."; - if( creatorp(ob) ) return "You cannot get stat information on a creator."; - cols = ((int *)this_player()->GetScreen())[0]; - tmp1 = (string)ob->GetCapName() + " aka " + (string)ob->GetShort() + - ", level " + (int)ob->GetLevel() + " " + (string)ob->GetGender(); - if( !(tmp2 = (string)ob->GetRace()) ) tmp2 = "blob"; - tmp1 += " " + tmp2; - if( !(tmp2 = (string)ob->GetClass()) ) tmp2 = "drifter"; - tmp1 += " " + capitalize(tmp2); - if( tmp2 = (string)ob->GetSpouse() ) - tmp1 += " (spouse: " + tmp2 + ")"; - lines = ({ center(tmp1, cols) }); - if( (int)ob->GetUndead() ) tmp1 = "Undead"; - else tmp1 = "Alive"; - if( (int)ob->GetSleeping() ) tmp1 += " / Sleeping"; - else tmp1 += " / Awake"; - if( (int)ob->GetParalyzed() ) tmp1 += " / Paralyzed"; - lines += ({ center(tmp1, cols), "" }); - lines += ({ center("Health: " +(int)ob->GetHealthPoints() + "/"+ - (int)ob->GetMaxHealthPoints() + " Magic: " + - (int)ob->GetMagicPoints() + "/" + - (int)ob->GetMaxMagicPoints() + " Stamina: " + - (int)ob->GetStaminaPoints() + "/" + - to_int((float)ob->GetMaxStaminaPoints()) + " Carry: " + - (int)ob->GetCarriedMass() + "/" + - (int)ob->GetMaxCarry(), cols) }); - lines += ({ center("Food: " + (int)ob->GetFood() + " " + - "Drink: " + (int)ob->GetDrink() + " " + - "Alcohol: " + (int)ob->GetAlcohol() + " " + - "Caffeine: " + (int)ob->GetCaffeine() + " " + - "Poison: " + (int)ob->GetPoison() + " ", cols) }); - lines += ({ center("Training Points: " + (int)ob->GetTrainingPoints()) }); - lines += ({ "", "Limbs:" }); - limbs = (string *)ob->GetWieldingLimbs(); - arr = map((string *)ob->GetLimbs(), - (: sprintf("%:-14s%s (%d) %d/%d", $1, - ((member_array($1, $(limbs)) == -1) ? " " : "*"), - (int)($(ob))->GetLimbClass($1), - (int)($(ob))->GetHealthPoints($1), - (int)($(ob))->GetMaxHealthPoints($1)) :)); - i = sizeof(arr); - while(i--) if( (y = strlen(arr[i])) > x ) x = y; - x = cols/(x+2); - lines += explode(format_page(arr, x), "\n") + ({ "", "Skills:" }); - arr = map((string *)ob->GetSkills(), - function(string skill, object who) { - mapping mp = (mapping)who->GetSkill(skill); - int x, max; - x = to_int(percent(mp["points"], - (int)who->GetMaxSkillPoints(skill, mp["level"]))); - max = ( mp["class"] == 1 ? 2 : 1 ) + who->GetLevel(); - max *= 2; - if( max < mp["level"] ) max = mp["level"]; - return sprintf("%:-18s (%d) %:2d%% - %d/%d", - skill, mp["class"], x, mp["level"], max); - }, ob); - i = sizeof(arr); - while(i--) if( (y = strlen(arr[i])) > x ) x = y; - x = cols/(x+2); - lines += explode(format_page(arr, x), "\n") + ({ "", "Stats:" }); - arr = map((string *)ob->GetStats(), - (: sprintf("%:-12s (%d) %d/%d", $1, - (int)($(ob))->GetStatClass($1), - (int)($(ob))->GetStatLevel($1), - (int)($(ob))->GetBaseStatLevel($1)) :)); - i = sizeof(arr); - x = 0; - while(i--) if( (y = strlen(arr[i])) > x ) x = y; - x =cols/(x+2); - lines += explode(format_page(arr, x), "\n"); - lines += ({ "", (string)ob->GetName()+" has amassed a net worth of " + - ( (int)ob->GetNetWorth() * currency_rate("gold") ) + " gold."}); - arr = filter( map((string *)ob->GetCurrencies(), - (: ($(ob))->GetCurrency($1) && - sprintf("%d %s", ($(ob))->GetCurrency($1), $1) :)), - (: $1 :)); - lines += ({ "Money on hand: "+implode(arr, ", ") }); - this_player()->eventPage(lines, "system"); - return 1; - } - - string GetHelp(string blah) { - return ("Syntax: stat \n\n" - "Displays statistical information on the living object named."); - } --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/creators/tellblock.c ds2.1/lib/cmds/creators/tellblock.c *** ds1.1/lib/cmds/creators/tellblock.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/tellblock.c Wed Jul 5 00:01:03 2006 *************** *** 19,23 **** void help() { write("Syntax: \n\n"+ ! "Toggles the blocking of tells on and off."); } --- 19,23 ---- void help() { write("Syntax: \n\n"+ ! "Toggles the blocking of tells on and off."); } diff -c -r --new-file ds1.1/lib/cmds/creators/trans.c ds2.1/lib/cmds/creators/trans.c *** ds1.1/lib/cmds/creators/trans.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/trans.c Wed Jul 5 00:01:03 2006 *************** *** 13,32 **** if( !args || args == "" ) return "Trans whom?"; if( !(ob = find_player(convert_name(args))) && !(ob = find_living(args)) ) ! return "No such being exists anywhere presently."; if( environment(ob) == environment(this_player()) ) ! return (string)ob->GetCapName() + " is right here."; message("system", "You have been summoned by " + ! (string)this_player()->GetName() + ".", ob); if( !((int)ob->eventMoveLiving(environment(this_player()))) ) ! return "Failed to move " + (string)ob->GetCapName() + "."; else message("system", "You trans " + (string)ob->GetCapName() + ! " to you.", this_player()); return 1; } void help() { message("help", "Syntax: \n\n" ! "Brings a living thing to your location.\n\n" ! "See also: goto", this_player()); } --- 13,38 ---- if( !args || args == "" ) return "Trans whom?"; if( !(ob = find_player(convert_name(args))) && !(ob = find_living(args)) ) ! return "No such being exists anywhere presently."; if( environment(ob) == environment(this_player()) ) ! return (string)ob->GetCapName() + " is right here."; ! if(archp(ob) && !archp(this_player())){ ! write("You can't trans an admin."); ! tell_player(ob, this_player()->GetName()+" just tried to trans you."); ! return 1; ! } ! ob->SetProperty("ReturnSite",base_name(environment(ob))); message("system", "You have been summoned by " + ! (string)this_player()->GetName() + ".", ob); if( !((int)ob->eventMoveLiving(environment(this_player()))) ) ! return "Failed to move " + (string)ob->GetCapName() + "."; else message("system", "You trans " + (string)ob->GetCapName() + ! " to you.", this_player()); return 1; } void help() { message("help", "Syntax: \n\n" ! "Brings a living thing to your location.\n\n" ! "See also: return, goto, move, expel", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/creators/transfer.c ds2.1/lib/cmds/creators/transfer.c *** ds1.1/lib/cmds/creators/transfer.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/transfer.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,59 ---- + /* /cmds/creators/transfer.c + * From the Dead Souls V Object Library + * Moves object from one place to another + * created by Descartes of Borg 961008 + * Version: @(#) transfer.c 1.2@(#) + * Last modified: 96/10/08 + */ + + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string args) { + object what, destination; + string a, b; + mixed res; + + if(!args || args == ""){ + return "Syntax: \n\n"; + } + + if( sscanf(args, "%s into %s", a, b) != 2 && + sscanf(args, "%s to %s", a, b) != 2 ) { + return "Syntax: \n\n"; + } + what = to_object(a); + destination = to_object(b); + if( !what ) { + return "Unable to find " + a + "."; + } + if( !destination ) { + return "Unable to find " + b + "."; + } + if( living(what) && living(destination) ) { + return "None of that nonsense."; + } + res = what->eventMove(destination); + if( !res ) { + return "Failed to transfer " + identify(what) + " into " + + identify(destination) + "."; + } + else if( res != 1 ) { + return res; + } + previous_object()->eventPrint("Transferred " + identify(what) + " into " + + identify(destination) + ".", MSG_SYSTEM); + if( living(what) ) { + what->eventDescribeEnvironment(); + } + return 1; + } + + string GetHelp() { + return ("Syntax: \n\n" + "Allows you to transfer the object you name into the container " + "you name.\n\n" + "See also: trans, expel, goto, return"); + } diff -c -r --new-file ds1.1/lib/cmds/creators/unquell.c ds2.1/lib/cmds/creators/unquell.c *** ds1.1/lib/cmds/creators/unquell.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/unquell.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,27 ---- + // By Magnafix 10-14-96 + // required addition of list_new_posts() in bboard daemon + #include + #include + + inherit LIB_COMMAND; + + + int cmd(string str){ + write("You snap your fingers, and permit hostilities to resume."); + say(this_player()->GetCapName()+" snaps "+possessive()+" fingers "+ + "and permits hostilities to resume."); + foreach(object combatant in get_livings(environment(this_player()))){ + combatant->eventUnQuell(); + if(combatant->GetInCombat()) tell_object(combatant,"You resume fighting."); + } + + return 1; + } + + + + string GetHelp(string str) { + return "Syntax: \n" + "Allows quelled combat to resume.\n" + "See also: quell\n"; + } diff -c -r --new-file ds1.1/lib/cmds/creators/vis.c ds2.1/lib/cmds/creators/vis.c *** ds1.1/lib/cmds/creators/vis.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/vis.c Wed Jul 5 00:01:03 2006 *************** *** 8,29 **** varargs int cmd(string str) { ! if(!this_player()->GetInvis()) { notify_fail("You are already visible.\n"); return 0; } this_player()->SetInvis(0); message("my_action", "You step out of the shadows.", this_player()); ! return 1; } int help() { ! write( @EndText Syntax: vis Effect: Makes you visible if you wern't already. EndText ! ); ! return 1; } --- 8,29 ---- varargs int cmd(string str) { ! if(!this_player()->GetInvis()) { notify_fail("You are already visible.\n"); return 0; } this_player()->SetInvis(0); message("my_action", "You step out of the shadows.", this_player()); ! return 1; } int help() { ! write( @EndText Syntax: vis Effect: Makes you visible if you wern't already. EndText ! ); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/creators/which.c ds2.1/lib/cmds/creators/which.c *** ds1.1/lib/cmds/creators/which.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/creators/which.c Wed Jul 5 00:01:03 2006 *************** *** 15,30 **** mixed cmd(string args) { string array dirs; string dir, msg; if( !args ) { return "You want to know information on which command?"; } ! if( !(dirs = CMD_D->GetPaths(args)) ) { return args + ": not found."; } msg = args + ":"; foreach(dir in dirs) { ! msg += "\n\t" + dir; } previous_object()->eventPrint(msg, MSG_SYSTEM); return 1; --- 15,39 ---- mixed cmd(string args) { string array dirs; string dir, msg; + int isverb; + dirs = ({}); + + isverb = 0; if( !args ) { return "You want to know information on which command?"; } ! if(member_array(args,keys(VERBS_D->GetVerbs())) != -1){ ! dirs += ({ (VERBS_D->GetVerbs())[args] }); ! isverb = 1; ! } ! else if( !(dirs = CMD_D->GetPaths(args)) ) { return args + ": not found."; } msg = args + ":"; foreach(dir in dirs) { ! if(isverb) msg += "\n\t" + dir; ! else msg += "\n\t" + dir + "/" + args + ".c"; } previous_object()->eventPrint(msg, MSG_SYSTEM); return 1; *************** *** 32,38 **** string GetHelp() { return ("Syntax: \n\n" ! "Gives you a listing of all directories in which a command " ! "object may be found.\n\n" ! "See also: help, man"); } --- 41,47 ---- string GetHelp() { return ("Syntax: \n\n" ! "Gives you a listing of all directories in which a command " ! "object may be found.\n\n" ! "See also: help, man"); } diff -c -r --new-file ds1.1/lib/cmds/creators/whomuffed.c ds2.1/lib/cmds/creators/whomuffed.c *** ds1.1/lib/cmds/creators/whomuffed.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/whomuffed.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,42 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + object player; + if(!str || str =="") { + if(!sizeof(this_player()->GetMuffed())) write("You are ignoring no one."); + else { + write("You are ignoring the following:\n"); + write(implode(filter(this_player()->GetMuffed(), (: capitalize($1) :)), "\n")+"\n"); + } + return 1; + } + + else str = lower_case(str); + if(!(player = find_player(str))){ + write("No such player to be found."); + return 1; + } + + if(!sizeof(player->GetMuffed())){ + write("That player is ignoring no one."); + return 1; + } + + else { + write(capitalize(str)+" is ignoring: \n"); + write(implode(filter(player->GetMuffed(), (: capitalize($1) :)), "\n")+"\n"); + } + return 1; + } + + void help() { + message("help", + "Syntax: whomuffed\n" + " whomuffed \n\n" + "This command lists who is ignored by the player specified.\n" + "See also: earmuff, unmuff\n\n", + this_player() ); + } + diff -c -r --new-file ds1.1/lib/cmds/creators/wiz.c ds2.1/lib/cmds/creators/wiz.c *** ds1.1/lib/cmds/creators/wiz.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/creators/wiz.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,21 ---- + /* /cmds/creators/wiz.c + * Created by Zin@Frontiers + * Sun Sep 21 21:00:16 1997 EDT + */ + + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + write("You speed to the Creators' Hall.\n"); + this_player()->eventMoveLiving("/domains/default/room/wiz_hall"); + return 1; + } + + void help() { + message("help", "Syntax: wiz\n\n" + "This command will move you to the Creators' Hall.\n\n", + this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/hm/.login ds2.1/lib/cmds/hm/.login *** ds1.1/lib/cmds/hm/.login Fri Jan 3 22:13:21 1997 --- ds2.1/lib/cmds/hm/.login Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - finger holle - honey HONEY! --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/hm/.login.bak ds2.1/lib/cmds/hm/.login.bak *** ds1.1/lib/cmds/hm/.login.bak Fri Jan 3 22:13:21 1997 --- ds2.1/lib/cmds/hm/.login.bak Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - finger holle - honey HONEY! --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/hm/.login.bak.bak ds2.1/lib/cmds/hm/.login.bak.bak *** ds1.1/lib/cmds/hm/.login.bak.bak Fri Jan 3 22:13:21 1997 --- ds2.1/lib/cmds/hm/.login.bak.bak Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - finger holle - honey HONEY! --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/hm/.login.bak.bak.bak ds2.1/lib/cmds/hm/.login.bak.bak.bak *** ds1.1/lib/cmds/hm/.login.bak.bak.bak Fri Jan 3 22:13:21 1997 --- ds2.1/lib/cmds/hm/.login.bak.bak.bak Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - finger holle - honey HONEY! --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/hm/.login.bak.bak.bak.bak ds2.1/lib/cmds/hm/.login.bak.bak.bak.bak *** ds1.1/lib/cmds/hm/.login.bak.bak.bak.bak Fri Jan 3 22:13:21 1997 --- ds2.1/lib/cmds/hm/.login.bak.bak.bak.bak Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - finger holle - honey HONEY! --- 0 ---- diff -c -r --new-file ds1.1/lib/cmds/players/biography.c ds2.1/lib/cmds/players/biography.c *** ds1.1/lib/cmds/players/biography.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/players/biography.c Tue Jul 11 18:30:58 2006 *************** *** 22,46 **** cols = ((int *)this_player()->GetScreen())[0]; tmp = ({ center("Biography for " + (string)this_player()->GetShort() + ! " on " + mud_name(), cols), "" }); birth = (int)this_player()->GetBirth(); x = query_year(birth); if( x < 0 ) yrstr = (-x) + " BN"; else yrstr = x + ""; tmp += ({ sprintf("%:-"+(cols/2)+"s%"+(cols/2)+"s", "Level: " + ! (int)this_player()->GetLevel(), "Age: " + ! ((time() - birth)/YEAR) + " years") }); tmp = ({ "You are " + (string)this_player()->GetMoralityDescription() ! + "." }); tmp += ({ sprintf("You were born on the %d%s day of %s, year %s.", ! query_date(birth), ordinal(query_date(birth)), ! query_month(birth), yrstr) }); m = (class marriage *)this_player()->GetMarriages(); if( !sizeof(m) ) tmp += ({ "You have never been married." }); else { class marriage marr; string town; ! marr = m[0]; if( !marr->DivorceDate ) { x = query_year(marr->WeddingDate); --- 22,46 ---- cols = ((int *)this_player()->GetScreen())[0]; tmp = ({ center("Biography for " + (string)this_player()->GetShort() + ! " on " + mud_name(), cols), "" }); birth = (int)this_player()->GetBirth(); x = query_year(birth); if( x < 0 ) yrstr = (-x) + " BN"; else yrstr = x + ""; tmp += ({ sprintf("%:-"+(cols/2)+"s%"+(cols/2)+"s", "Level: " + ! (int)this_player()->GetLevel(), "Age: " + ! ((time() - birth)/YEAR) + " years") }); tmp = ({ "You are " + (string)this_player()->GetMoralityDescription() ! + "." }); tmp += ({ sprintf("You were born on the %d%s day of %s, year %s.", ! query_date(birth), ordinal(query_date(birth)), ! query_month(birth), yrstr) }); m = (class marriage *)this_player()->GetMarriages(); if( !sizeof(m) ) tmp += ({ "You have never been married." }); else { class marriage marr; string town; ! marr = m[0]; if( !marr->DivorceDate ) { x = query_year(marr->WeddingDate); *************** *** 50,57 **** if( !town || town == "wilderness" ) town = "."; else town = " in " + town + "."; tmp += ({ "You married " + marr->Spouse + " the " + ! ordinal(query_date(marr->WeddingDate)) + " of " + ! query_month(marr->WeddingDate) + " " + yrstr + town }); if( sizeof(m) > 1 ) m = m[1..]; else m = ({}); } --- 50,57 ---- if( !town || town == "wilderness" ) town = "."; else town = " in " + town + "."; tmp += ({ "You married " + marr->Spouse + " the " + ! ordinal(query_date(marr->WeddingDate)) + " of " + ! query_month(marr->WeddingDate) + " " + yrstr + town }); if( sizeof(m) > 1 ) m = m[1..]; else m = ({}); } *************** *** 59,65 **** tmp += ({ "Past marriages:" }); while(i--) { string yrstr2; ! marr = m[i]; x = query_year(marr->WeddingDate); if( x < 0 ) yrstr = (-x) + " BN"; --- 59,65 ---- tmp += ({ "Past marriages:" }); while(i--) { string yrstr2; ! marr = m[i]; x = query_year(marr->WeddingDate); if( x < 0 ) yrstr = (-x) + " BN"; *************** *** 71,113 **** if( !town || town == "wilderness" ) town = ""; else town = " in " + town; tmp += ({ "You married " + marr->Spouse + " " + ! query_month(marr->WeddingDate) + " " + ! query_date(marr->WeddingDate) + ", " + yrstr + ! town + ", divorced " + ! query_month(marr->DivorceDate) + " " + ! query_date(marr->DivorceDate) + ", " + yrstr2 + "." ! }); } } } deaths = (mapping *)this_player()->GetDeaths(); if( !(x = sizeof(deaths)) ) ! tmp += ({ "You have never suffered the pain of death." }); else { mapping *d1, *d2; ! tmp += ({ "", "Death has cast its shadow over you on the following " + ! consolidate(x, "occasion") + ":" }); if( x == 1 ) { d1 = deaths[0..0]; d2 = ({}); } else { - x = x/2; d1 = deaths[0..(x-1)]; d2 = deaths[x..]; } for(i=0; i= sizeof(d1)) ? "" : ! d1[i]["enemy"], ! (i >= sizeof(d2)) ? "" : ! d2[i]["enemy"]) }); } kills = (mapping)STATISTICS_D->GetKills((string)this_player()->GetKeyName()); npcs = sort_array(keys(kills), 1); if( !(x = sizeof(npcs)) ) ! tmp += ({ "You have never brought harm to another." }); else { tmp += ({ "","You are responsible for the deaths of the following:" }); if( x < 3 ) { --- 71,112 ---- if( !town || town == "wilderness" ) town = ""; else town = " in " + town; tmp += ({ "You married " + marr->Spouse + " " + ! query_month(marr->WeddingDate) + " " + ! query_date(marr->WeddingDate) + ", " + yrstr + ! town + ", divorced " + ! query_month(marr->DivorceDate) + " " + ! query_date(marr->DivorceDate) + ", " + yrstr2 + "." ! }); } } } deaths = (mapping *)this_player()->GetDeaths(); if( !(x = sizeof(deaths)) ) ! tmp += ({ "You have never suffered the pain of death." }); else { mapping *d1, *d2; ! tmp += ({ "", "Death has cast its shadow over you on the following " + ! consolidate(x, "occasion") + ":" }); if( x == 1 ) { d1 = deaths[0..0]; d2 = ({}); } else { d1 = deaths[0..(x-1)]; d2 = deaths[x..]; } for(i=0; i= sizeof(d1)) ? "" : ! d1[i]["enemy"], ! (i >= sizeof(d2)) ? "" : ! d2[i]["enemy"]) }); } kills = (mapping)STATISTICS_D->GetKills((string)this_player()->GetKeyName()); npcs = sort_array(keys(kills), 1); if( !(x = sizeof(npcs)) ) ! tmp += ({ "You have never brought harm to another." }); else { tmp += ({ "","You are responsible for the deaths of the following:" }); if( x < 3 ) { *************** *** 123,135 **** col3 = npcs[(2*x)..]; } for(i=0; i= sizeof(col1)) ? "" : ! col1[i] + " (" + kills[col1[i]] + ")", ! (i >= sizeof(col2)) ? "" : ! col2[i] + " (" + kills[col2[i]] + ")", ! (i >= sizeof(col3)) ? "" : ! col3[i] + " (" + kills[col3[i]] + ")") }); } this_player()->eventPage(tmp, MSG_SYSTEM); return 1; --- 122,134 ---- col3 = npcs[(2*x)..]; } for(i=0; i= sizeof(col1)) ? "" : ! col1[i] + " (" + kills[col1[i]] + ")", ! (i >= sizeof(col2)) ? "" : ! col2[i] + " (" + kills[col2[i]] + ")", ! (i >= sizeof(col3)) ? "" : ! col3[i] + " (" + kills[col3[i]] + ")") }); } this_player()->eventPage(tmp, MSG_SYSTEM); return 1; *************** *** 137,145 **** string GetHelp(string str) { return ("Syntax: \n\n" ! "Biography gives you a full account of the sort of life you " ! "have lived on " + mud_name() + ". This information details " ! "such things as your birth, deaths, marriages, and other life " ! "information.\n\n" ! "See also: score"); } --- 136,144 ---- string GetHelp(string str) { return ("Syntax: \n\n" ! "Biography gives you a full account of the sort of life you " ! "have lived on " + mud_name() + ". This information details " ! "such things as your birth, deaths, marriages, and other life " ! "information.\n\n" ! "See also: score"); } diff -c -r --new-file ds1.1/lib/cmds/players/brief.c ds2.1/lib/cmds/players/brief.c *** ds1.1/lib/cmds/players/brief.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/players/brief.c Wed Jul 5 00:01:03 2006 *************** *** 2,30 **** * A command which allows players to toggle brief room descriptions * Created by Blitz at NM-IVD */ ! #include ! inherit LIB_DAEMON; ! mixed cmd(string str) { ! if( !sizeof(str) ) ! return "Syntax: brief "; ! str = lower_case(str); ! if( str != "on" && str != "off" ) ! return "You can only turn brief 'on' or 'off'"; ! this_player()->SetBriefMode(str == "on"); ! message("system", ! "Brief mode turned "+str+".", ! this_player() ); ! return 1; } ! void help() { ! message("help", ! "Syntax: brief on\n" ! " brief off\n\n" ! "This command allows you to toggle brief room descriptions on or off.\n\n", ! this_player() ); } ! --- 2,30 ---- * A command which allows players to toggle brief room descriptions * Created by Blitz at NM-IVD */ ! #include ! inherit LIB_DAEMON; ! mixed cmd(string str) { ! if( !sizeof(str) ) ! return "Syntax: brief "; ! str = lower_case(str); ! if( str != "on" && str != "off" ) ! return "You can only turn brief 'on' or 'off'"; ! this_player()->SetBriefMode(str == "on"); ! message("system", ! "Brief mode turned "+str+".", ! this_player() ); ! return 1; } ! void help() { ! message("help", ! "Syntax: brief on\n" ! " brief off\n\n" ! "This command allows you to toggle brief room descriptions on or off.\n\n", ! this_player() ); } ! diff -c -r --new-file ds1.1/lib/cmds/players/consider.c ds2.1/lib/cmds/players/consider.c *** ds1.1/lib/cmds/players/consider.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/consider.c Tue Jul 11 18:30:58 2006 *************** *** 0 **** --- 1,129 ---- + #include + #include + + inherit LIB_DAEMON; + + int eventConsider(object whom, object opponent){ + int score = 0; + int tmp = 0; + int protection = 0; + string *attack_types = ({}); + object *dam_types = ({}); + object *weapons = filter(all_inventory(whom), (: $1->GetWielded() :)); + object *enemy_armor = filter(all_inventory(opponent), (: $1->GetWorn() :)); + enemy_armor = filter(enemy_armor, (: !($1->GetWielded()) :) ); + + if(sizeof(weapons)){ + foreach(object weapon in weapons){ + if(weapon->GetWeaponType() && whom->GetSkill(weapon->GetWeaponType()+" attack")){ + attack_types += ({ weapon->GetWeaponType() }); + score += ( whom->GetSkill(weapon->GetWeaponType()+" attack")["level"] ) * 3; + } + if(weapon->GetClass()) + score += ( weapon->GetClass() ) * 6; + if(weapon->GetHands() > 1) { + if(!(whom->GetSkill("multi-hand"))) score /= 3; + } + } + if(sizeof(weapons) >1) { + if(!(whom->GetSkill("multi-weapon"))) score /= 3; + } + } + + else if((whom->GetMelee())) { + if(whom->GetSkill("melee attack")) + score += (((whom->GetSkill("melee attack")["level"]) * 3)); + } + if(!sizeof(attack_types)) attack_types = ({"blunt"}); + foreach(string Type in attack_types){ + int DamType = 0; + int tmp_prot = 0; + object *qual_armor = ({}); + + switch(Type){ + case "blade" : DamType = BLADE; break; + case "blunt" : DamType = BLUNT; break; + case "knife" : DamType = KNIFE; break; + case "water" : DamType = WATER; break; + case "shock" : DamType = SHOCK; break; + case "cold" : DamType = COLD; break; + case "heat" : DamType = HEAT; break; + case "gas" : DamType = GAS; break; + case "acid" : DamType = ACID; break; + case "magic" : DamType = MAGIC; break; + case "poison" : DamType = POISON; break; + case "disease" : DamType = DISEASE; break; + case "trauma" : DamType = TRAUMA; break; + default : DamType = BLUNT; break; + } + + foreach(object armor in enemy_armor){ + tmp_prot += armor->GetProtection(DamType); + if(armor->GetProtection(DamType)) qual_armor += ({ armor }); + } + if(sizeof(qual_armor)) protection += tmp_prot / sizeof(qual_armor); + tmp_prot = 0; + DamType = 0; + } + + + + score += whom->GetStatLevel("speed") * 2; + score += whom->GetStatLevel("strength") * 3; + score += whom->GetMaxHealthPoints() / 15; + score += protection; + + return score; + } + + mixed cmd(string str) { + object thing; + int totalscore, myscore, theirscore; + + if(!str){ + write("Consider what?"); + return 1; + } + if(!(thing = present(str,environment(this_player())))){ + write("That isn't here."); + return 1; + } + if(!living(thing)){ + write("That isn't a living thing."); + return 1; + } + + theirscore = eventConsider(thing, this_player()); + myscore = eventConsider(this_player(), thing); + + totalscore = myscore - theirscore; + if(totalscore > 100) write("Piece of cake."); + else if(totalscore > 80) write("No problem."); + else if(totalscore > 60) write("Very easy."); + else if(totalscore > 40) write("Fairly easy."); + else if(totalscore > 20) write("You'd probably do fine"); + else if(totalscore > 0) write("A fair match."); + else if(totalscore > -20) write("A workout."); + else if(totalscore > -40) write("A serious match."); + else if(totalscore > -60) write("A major challenge."); + else if(totalscore > -80) write("An unwise choice."); + else if(totalscore > -100) write("Really a bad idea."); + else write("Suicide."); + return 1; + } + + + void help() { + message("help", + "Syntax: consider \n" + "Gives you an idea of how tough a creature would be to defeat " + "in combat. Gauges relative strengths, skills, weapons, " + "armor, levels, health, and so on. The resulting comparison " + "may not be very useful, because a change during combat (such " + "as the opponent changing weapons) or items of unusual class " + "or protection (such as magical armor) may not be taken into " + "account." + "\n", + this_player() ); + } + diff -c -r --new-file ds1.1/lib/cmds/players/converse.c ds2.1/lib/cmds/players/converse.c *** ds1.1/lib/cmds/players/converse.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/players/converse.c Wed Jul 5 00:01:03 2006 *************** *** 14,24 **** mixed cmd(string args) { message("system", "Entering conversation mode. Continue entering things " ! "you wish 'said' until done.", this_player()); message("system", "When done, enter a '.' alone on a line like in edit.", ! this_player()); message("system", "______________________________________________________" ! , this_player()); input_to( (: eventChat :)); return 1; } --- 14,24 ---- mixed cmd(string args) { message("system", "Entering conversation mode. Continue entering things " ! "you wish 'said' until done.", this_player()); message("system", "When done, enter a '.' alone on a line like in edit.", ! this_player()); message("system", "______________________________________________________" ! , this_player()); input_to( (: eventChat :)); return 1; } *************** *** 34,44 **** void help() { message("help", "Syntax: \n\n" ! "Puts you into conversation mode, which means that anything you " ! "type will act as if you are placing the \"say\" command before " ! "it. Once in conversation mode, you exit the same way you do " ! "from the mail or bulletin board editor, that is, by typing " ! "a '.' alone on a line. You may also issue commands while " ! "in conversation mode by putting a ! before whatever you type.\n\n" ! "See also: say, tell", this_player()); } --- 34,44 ---- void help() { message("help", "Syntax: \n\n" ! "Puts you into conversation mode, which means that anything you " ! "type will act as if you are placing the \"say\" command before " ! "it. Once in conversation mode, you exit the same way you do " ! "from the mail or bulletin board editor, that is, by typing " ! "a '.' alone on a line. You may also issue commands while " ! "in conversation mode by putting a ! before whatever you type.\n\n" ! "See also: say, tell", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/customize.c ds2.1/lib/cmds/players/customize.c *** ds1.1/lib/cmds/players/customize.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/customize.c Wed Jul 5 00:01:03 2006 *************** *** 14,24 **** mixed tmp; string stat; int amt; ! if( !args || args == "" ) { amt = (int)this_player()->GetCustomStats(); this_player()->eventPrint("You have " + amt + " points left to " ! "spend on stats.", MSG_SYSTEM); return 1; } amt = to_int((tmp = explode(args, " "))[<1]); --- 14,24 ---- mixed tmp; string stat; int amt; ! if( !args || args == "" ) { amt = (int)this_player()->GetCustomStats(); this_player()->eventPrint("You have " + amt + " points left to " ! "spend on stats.", MSG_SYSTEM); return 1; } amt = to_int((tmp = explode(args, " "))[<1]); *************** *** 28,45 **** if( stringp(tmp) ) return tmp; if( !tmp ) return "Failed to raise stat."; this_player()->eventPrint("Your " + stat + " is now at " + tmp + ! ", and you have " + ! (int)this_player()->GetCustomStats() + ! " points left to spend.", MSG_SYSTEM); return 1; } string GetHelp(string str) { return ("Syntax: \n" ! " \n\n" ! "Allows you to spend customization points to boost the " ! "stats with which you were born. Once you are down to 0 " ! "customization points, you never get any back.\n" ! "Using this command without arguments tells you how many " ! "points you have left to spend."); } --- 28,45 ---- if( stringp(tmp) ) return tmp; if( !tmp ) return "Failed to raise stat."; this_player()->eventPrint("Your " + stat + " is now at " + tmp + ! ", and you have " + ! (int)this_player()->GetCustomStats() + ! " points left to spend.", MSG_SYSTEM); return 1; } string GetHelp(string str) { return ("Syntax: \n" ! " \n\n" ! "Allows you to spend customization points to boost the " ! "stats with which you were born. Once you are down to 0 " ! "customization points, you never get any back.\n" ! "Using this command without arguments tells you how many " ! "points you have left to spend."); } diff -c -r --new-file ds1.1/lib/cmds/players/date.c ds2.1/lib/cmds/players/date.c *** ds1.1/lib/cmds/players/date.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/date.c Wed Jul 5 00:01:03 2006 *************** *** 2,39 **** * A simple command which displays current date and time * Blitz@NM-IVD */ ! #include #include #include ! ! mixed cmd(string unused) { ! string *parts, year, date, time; ! int x, hour, min, sec; ! ! time = (string)this_player()->GetTimeZone() || localtime(time())[LT_ZONE]; ! x = (int)TIME_D->GetOffSet(time) * 3600; ! time = ctime( time() + x ); ! x = sizeof(parts = explode(time, " ")); ! year = parts[x - 1]; ! sscanf(parts[x - 2], "%d:%d:%d", hour, min, sec); ! if( !hour ) hour = 12; ! message("info", ! sprintf("Time: %d:%s%d %s\nDate: %s, %s", ! (hour>12 ? (hour-12) : hour), ! (min < 10 ? "0" : ""), ! min, ! (hour>11 ? "pm" : "am"), ! implode(parts[0..(x-3)], " "), ! year), ! this_player() ); ! return 1; } ! void help() { ! message("help", ! "Syntax: date\n\n" ! "Displays current time and date in your local time if you have it " ! "specified.", ! this_player() ); } --- 2,47 ---- * A simple command which displays current date and time * Blitz@NM-IVD */ ! #include + #include #include #include ! ! mixed cmd(string timezone) { ! string *parts, year, time; ! int offset, x, hour, min, sec; ! ! if(timezone && timezone != "" && valid_timezone(timezone)){ ! write(local_time(timezone)); ! return 1; ! } ! ! offset = (int)TIME_D->GetOffset(local_time()[9]); ! offset += EXTRA_TIME_OFFSET; ! if(query_os_type() != "windows" ) ! x = offset * 3600; ! else x = 0; ! time = ctime( time() + x ); ! x = sizeof(parts = explode(time, " ")); ! year = parts[x - 1]; ! sscanf(parts[x - 2], "%d:%d:%d", hour, min, sec); ! if( !hour ) hour = 12; ! message("info", ! sprintf("Time: %d:%s%d %s\nDate: %s, %s", ! (hour>12 ? (hour-12) : hour), ! (min < 10 ? "0" : ""), ! min, ! (hour>11 ? "pm" : "am"), ! implode(parts[0..(x-3)], " "), ! year), ! this_player() ); ! return 1; } ! void help() { ! message("help", ! "Syntax: date\n\n" ! "Displays current time and date in local time.", ! this_player() ); } diff -c -r --new-file ds1.1/lib/cmds/players/earmuff.c ds2.1/lib/cmds/players/earmuff.c *** ds1.1/lib/cmds/players/earmuff.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/earmuff.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,30 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + if(!str || str =="") { + if(!sizeof(this_player()->GetMuffed())) write("You are ignoring no one."); + else { + write("You are ignoring the following name(s):\n"); + write(implode(filter(this_player()->GetMuffed(), (: capitalize($1) :)), "\n")+"\n"); + } + return 1; + } + else this_player()->AddMuffed(str); + write("You add "+capitalize(str)+" to your earmuffed list."); + return 1; + } + + void help() { + message("help", + "Syntax: earmuff\n" + " earmuff \n" + " earmuff @\n\n" + "This command allows you to ignore channel messages from the name specified.\n" + "You can also earmuff all channel messages coming from a " + "specific mud, for example: earmuff @Spammy Mud II\n" + "See also: whomuffed, unmuff\n\n", + this_player() ); + } + diff -c -r --new-file ds1.1/lib/cmds/players/emote.c ds2.1/lib/cmds/players/emote.c *** ds1.1/lib/cmds/players/emote.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/emote.c Tue Jul 11 18:30:58 2006 *************** *** 11,38 **** mixed cmd(string args) { if( !creatorp(this_player()) && !avatarp(this_player()) ) { if( (int)this_player()->GetStaminaPoints() < 1 ) ! return "You are too tired."; } if( !args || args == "" ) { message("my_action", "You are feeling emotional.", this_player()); message("other_action", (string)this_player()->GetName() + ! " looks emotional.", environment(this_player()), ! ({ this_player() })); return 1; } if( args[0] != '\'' ) args = " " + args; message("my_action", "You emote: " + (string)this_player()->GetName() + ! args, this_player()); message("other_action", (string)this_player()->GetName() + args, ! environment(this_player()), ({ this_player() }) ); return 1; } void help() { message("help", "Syntax: \n\n" ! "Places any message you specify directly after your name. For " ! "example, \"emote smiles.\" would have others see " ! "\"Descartes smiles.\". Non-avatars lose a stamina point for " ! "each emote to discourage abuse.", this_player()); } --- 11,39 ---- mixed cmd(string args) { if( !creatorp(this_player()) && !avatarp(this_player()) ) { if( (int)this_player()->GetStaminaPoints() < 1 ) ! return "You are too tired."; } if( !args || args == "" ) { message("my_action", "You are feeling emotional.", this_player()); message("other_action", (string)this_player()->GetName() + ! " looks emotional.", environment(this_player()), ! ({ this_player() })); return 1; } if( args[0] != '\'' ) args = " " + args; message("my_action", "You emote: " + (string)this_player()->GetName() + ! args, this_player()); message("other_action", (string)this_player()->GetName() + args, ! environment(this_player()), ({ this_player() }) ); return 1; } void help() { message("help", "Syntax: \n\n" ! "Places any message you specify directly after your name. For " ! "example, \"emote smiles.\" would have others see " ! "\"Descartes smiles.\". Non-avatars lose a stamina point for " ! "each emote to discourage abuse.\n" ! "", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/env.c ds2.1/lib/cmds/players/env.c *** ds1.1/lib/cmds/players/env.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/env.c Tue Jul 11 18:30:58 2006 *************** *** 0 **** --- 1,18 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string args) { + write("Screen: \t\t"+identify(this_player()->GetScreen())); + write("Terminal: \t\t"+this_player()->GetTerminal()); + write("Brief mode: \t\t"+ ( (this_player()->GetBriefMode()) ? "on" : "off" )); + if(creatorp(this_player())) + write("Debug mode: \t\t"+ ( (this_player()->GetProperty("debug")) ? "on" : "off" )); + return 1; + } + + void help() { + message("help", "Syntax: \n\n" + "Displays your basic interface and play settings. " + + "See also: brief, terminal, screen", this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/players/faq.c ds2.1/lib/cmds/players/faq.c *** ds1.1/lib/cmds/players/faq.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/faq.c Wed Jul 5 00:01:03 2006 *************** *** 16,22 **** int cols, i, maxi, x, y; message("help", mud_name() + " has the following FAQ lists:", ! this_player()); cols = ((int *)this_player()->GetScreen())[0]; i = sizeof(files = get_dir(DIR_FAQS "/")); while(i--) if( (y =strlen(files[i])) > x ) x = y; --- 16,22 ---- int cols, i, maxi, x, y; message("help", mud_name() + " has the following FAQ lists:", ! this_player()); cols = ((int *)this_player()->GetScreen())[0]; i = sizeof(files = get_dir(DIR_FAQS "/")); while(i--) if( (y =strlen(files[i])) > x ) x = y; *************** *** 32,39 **** static void GetFAQ(string args) { string file; ! ! if( !args || args == "" ) args = "general"; if( file_size(file = DIR_FAQS "/" + args) < 0 ) { message("error", "No such FAQ available.", this_player()); return; --- 32,40 ---- static void GetFAQ(string args) { string file; ! //bugfix courtesy of Manchi ! if( !args || args == "" || args == "y" || args == "Y" || lower_case(args) == "yes") ! args = "general"; if( file_size(file = DIR_FAQS "/" + args) < 0 ) { message("error", "No such FAQ available.", this_player()); return; *************** *** 47,60 **** void help() { message("help", "Syntax: \n\n" ! "If you specify a particular FAQ to read, this command will " ! "display that FAQ for you. If you fail to specify a FAQ, it " ! "will give you a list of FAQs from which to choose. FAQ " ! "stands for Frequently Asked Questions. Reading the FAQs is " ! "a good way of coming to understand topics basic to " + ! mud_name() + ".\n\n" ! "See also: help" + (creatorp(this_player()) ? ", man" : ""), ! this_player()); } ! --- 48,61 ---- void help() { message("help", "Syntax: \n\n" ! "If you specify a particular FAQ to read, this command will " ! "display that FAQ for you. If you fail to specify a FAQ, it " ! "will give you a list of FAQs from which to choose. FAQ " ! "stands for Frequently Asked Questions. Reading the FAQs is " ! "a good way of coming to understand topics basic to " + ! mud_name() + ".\n\n" ! "See also: help" + (creatorp(this_player()) ? ", man" : ""), ! this_player()); } ! diff -c -r --new-file ds1.1/lib/cmds/players/hist.c ds2.1/lib/cmds/players/hist.c *** ds1.1/lib/cmds/players/hist.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/hist.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,19 ---- + #include + #include + #include + + inherit LIB_DAEMON; + + mixed cmd(string args) { + if(!args) + this_player()->eventPrint("Syntax: "); + + this_player()->eventPrint("Retrieving history..."); + return CHAT_D->cmdLast(args); + return 1; + } + + string GetHelp(string topic) { + return ("Syntax: \n" + "Gives you a list of the hist of a channel "); + } diff -c -r --new-file ds1.1/lib/cmds/players/idle.c ds2.1/lib/cmds/players/idle.c *** ds1.1/lib/cmds/players/idle.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/idle.c Wed Jul 5 00:01:03 2006 *************** *** 2,35 **** * Simple command which displays named player's idle time * Recreated by Blitz@Dead Souls 960108 */ ! mixed cmd(string args) { int x; object who; ! if( !sizeof(args) ) return "Syntax: idle "; args = convert_name(args); who = find_player(args); if( !who || who->GetInvis() ) ! return "Unable to locate anyone by that name."; if( !interactive(who) ) ! return (string)who->GetName() + " is link dead."; x = query_idle(who); if( x > 4 ) { ! this_player()->eventPrint( sprintf("%s has been idle for %s%s.", ! (string)who->GetName(), ! ( x>59 ? ( consolidate(x/60, "one minute") + " and " ) : "" ), ! consolidate(x%60, "one second")) ); ! } else this_player()->eventPrint((string)who->GetName() + " is " ! "not idle."); return 1; } ! string GetHelp(string str) { return "Syntax: idle \n\n" ! "Displays named user's idle time. A user's \"idle time\" is " ! "the amount of time since the named user last sent input " ! "to the MUD."; } --- 2,35 ---- * Simple command which displays named player's idle time * Recreated by Blitz@Dead Souls 960108 */ ! mixed cmd(string args) { int x; object who; ! if( !sizeof(args) ) return "Syntax: idle "; args = convert_name(args); who = find_player(args); if( !who || who->GetInvis() ) ! return "Unable to locate anyone by that name."; if( !interactive(who) ) ! return (string)who->GetName() + " is link dead."; x = query_idle(who); if( x > 4 ) { ! this_player()->eventPrint( sprintf("%s has been idle for %s%s.", ! (string)who->GetName(), ! ( x>59 ? ( consolidate(x/60, "one minute") + " and " ) : "" ), ! consolidate(x%60, "one second")) ); ! } else this_player()->eventPrint((string)who->GetName() + " is " ! "not idle."); return 1; } ! string GetHelp(string str) { return "Syntax: idle \n\n" ! "Displays named user's idle time. A user's \"idle time\" is " ! "the amount of time since the named user last sent input " ! "to the MUD."; } diff -c -r --new-file ds1.1/lib/cmds/players/inventory.c ds2.1/lib/cmds/players/inventory.c *** ds1.1/lib/cmds/players/inventory.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/inventory.c Wed Jul 5 00:01:03 2006 *************** *** 13,19 **** mixed cmd(string args) { if( (int)this_player()->GetInCombat() ) ! this_player()->SetAttack(0, (: eventInventory :), ROUND_OTHER); else eventInventory(); return 1; } --- 13,19 ---- mixed cmd(string args) { if( (int)this_player()->GetInCombat() ) ! this_player()->SetAttack(0, (: eventInventory :), ROUND_OTHER); else eventInventory(); return 1; } *************** *** 25,32 **** int i; shorts = map(filter(all_inventory(this_player()), ! (: !((int)$1->GetInvis(this_player())) :)), ! (: (string)$1->GetEquippedShort() :)); borg = ([]); if( !(i = sizeof(shorts)) ) { message("system", "You are carrying nothing.", this_player()); --- 25,32 ---- int i; shorts = map(filter(all_inventory(this_player()), ! (: !((int)$1->GetInvis(this_player())) :)), ! (: (string)$1->GetEquippedShort() :)); borg = ([]); if( !(i = sizeof(shorts)) ) { message("system", "You are carrying nothing.", this_player()); *************** *** 38,51 **** i = sizeof(shorts = keys(borg)); while(i--) ret += capitalize(consolidate(borg[shorts[i]], shorts[i]))+"\n"; message("look", ret, this_player()); ! message("other_action", (string)this_player()->GetName() + " checks " + ! possessive(this_player()) + " possessions.", ! environment(this_player()), ({ this_player() })); } void help() { message("help", "Syntax: \n\n" ! "Lists all items you are carrying currently. This command " ! "will take up one round of combat if you happen to be in " ! "combat.", this_player()); } --- 38,52 ---- i = sizeof(shorts = keys(borg)); while(i--) ret += capitalize(consolidate(borg[shorts[i]], shorts[i]))+"\n"; message("look", ret, this_player()); ! if(!this_player()->GetInvis()) ! message("other_action", (string)this_player()->GetName() + " checks " + ! possessive(this_player()) + " possessions.", ! environment(this_player()), ({ this_player() })); } void help() { message("help", "Syntax: \n\n" ! "Lists all items you are carrying currently. This command " ! "will take up one round of combat if you happen to be in " ! "combat.", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/kills.c ds2.1/lib/cmds/players/kills.c *** ds1.1/lib/cmds/players/kills.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/kills.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,45 ---- + #include + + inherit LIB_DAEMON; + + mapping kills = ([]); + + mixed cmd(string args) { + string *stats; + string killfile, ret, tmp, name; + int i, x, y; + + name = lower_case(this_player()->GetKeyName()); + killfile = "/save/kills/"+name[0..0]+"/"+name; + if(!file_exists(killfile)) { + write("You have no kills to your name."); + return 1; + } + kills = restore_variable(read_file(killfile)); + if(!sizeof(kills)){ + write("You have never harmed a living thing."); + return 1; + } + ret = "You are " +(string)this_player()->GetShort() + ", level " + + (int)this_player()->GetLevel(); + if( (tmp = (string)this_player()->GetClass()) ) + ret += " " + capitalize(tmp); + else ret += " Drifter"; + ret += " (" + (string)this_player()->GetRace() + ")\n"; + ret+= "Your list of victories comprises the following:\n\n"; + stats = map(keys(kills), + (: sprintf("%:-20s: %:-1i", $1, + kills[$1]) :)); + i = sizeof(stats); + while(i--) if( (y = strlen(stats[i])) > x ) x = y; + x = ((int *)this_player()->GetScreen())[0]/(x+2); + ret += format_page(stats, x); + message("system", ret, this_player()); + return 1; + } + + void help() { + message("help", "Syntax: \n\n" + "A list of your victories." + "\n\n",this_player()); + } diff -c -r --new-file ds1.1/lib/cmds/players/language.c ds2.1/lib/cmds/players/language.c *** ds1.1/lib/cmds/players/language.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/language.c Wed Jul 12 13:29:17 2006 *************** *** 0 **** --- 1,31 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + mapping FluencyMap = ([]); + string *langs = this_player()->GetLanguages(); + + foreach(string lang in langs){ + FluencyMap[lang] = this_player()->GetLanguageLevel(lang); + } + + if(this_player()->GetPolyglot()){ + write("You understand all languages with 100% proficiency."); + } + + write("You speak: "); + foreach(string key, int val in FluencyMap){ + write(capitalize(key)+" with "+val+"% proficiency."); + } + + return 1; + } + + void help() { + message("help", + "Syntax: language\n\n" + "This command reports which languages you speak and understand.\n\n", + this_player() ); + } + diff -c -r --new-file ds1.1/lib/cmds/players/lines.c ds2.1/lib/cmds/players/lines.c *** ds1.1/lib/cmds/players/lines.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/lines.c Wed Jul 5 00:01:03 2006 *************** *** 2,46 **** // A utility to help wizards and players keep track of what lines they're // on, and to them turn all off and on with one command. // by Gregon@Dead Souls ! ! int cmd(string str) { ! ! string *channels; ! int i; ! ! channels = distinct_array((string *)this_player()->GetChannels()); ! ! if(!str) { ! for(i=0; iGetBlocked(channels[i])) ! message("info","You are blocking "+channels[i]+".",this_player()); ! else message("info","You are not blocking "+channels[i]+".",this_player()); ! } ! return 1; ! } ! ! if(str=="on"){ ! for(i=0; iGetBlocked(channels[i])) ! this_player()->SetBlocked(channels[i]); ! } ! return 1; ! } ! ! if(str=="off"){ ! for(i=0; iGetBlocked(channels[i])) ! this_player()->SetBlocked(channels[i]); ! } ! return 1; ! } ! } ! void help(){ ! message("help","Syntax: lines -or- lines [on|off]\n\n" ! "With no argument this command will display the status " ! "of the lines to which you have access. With the argument on|off " ! "it will turn all of the lines on or off.",this_player()); } --- 2,46 ---- // A utility to help wizards and players keep track of what lines they're // on, and to them turn all off and on with one command. // by Gregon@Dead Souls ! ! int cmd(string str) { ! ! string *channels; ! int i; ! ! channels = distinct_array((string *)this_player()->GetChannels()); ! ! if(!str) { ! for(i=0; iGetBlocked(channels[i])) ! message("info","You are blocking "+channels[i]+".",this_player()); ! else message("info","You are not blocking "+channels[i]+".",this_player()); ! } ! return 1; ! } ! ! if(str=="on"){ ! for(i=0; iGetBlocked(channels[i])) ! this_player()->SetBlocked(channels[i]); ! } ! return 1; ! } ! ! if(str=="off"){ ! for(i=0; iGetBlocked(channels[i])) ! this_player()->SetBlocked(channels[i]); ! } ! return 1; ! } ! } ! void help(){ ! message("help","Syntax: lines -or- lines [on|off]\n\n" ! "With no argument this command will display the status " ! "of the lines to which you have access. With the argument on|off " ! "it will turn all of the lines on or off.",this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/locate.c ds2.1/lib/cmds/players/locate.c *** ds1.1/lib/cmds/players/locate.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/locate.c Wed Jul 5 00:01:03 2006 *************** *** 18,27 **** void help() { message("help", "Syntax: \n\n" ! "This command allows you to know on which MUDs connected " ! "through the Intermud 3 network have someone using the " ! "name you specify. Note that this person may not actually be " ! "the person you think it is, as nothing prevents two different " ! "people from using the same name on different MUDs.\n\n" ! "See also: mail, mudlist, rwho, tell", this_player()); } --- 18,27 ---- void help() { message("help", "Syntax: \n\n" ! "This command allows you to know on which MUDs connected " ! "through the Intermud 3 network have someone using the " ! "name you specify. Note that this person may not actually be " ! "the person you think it is, as nothing prevents two different " ! "people from using the same name on different MUDs.\n\n" ! "See also: mail, mudlist, rwho, tell", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/money.c ds2.1/lib/cmds/players/money.c *** ds1.1/lib/cmds/players/money.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/money.c Wed Jul 5 00:01:03 2006 *************** *** 14,37 **** int i, tmp; if(str) return 0; /* to allow the wiz command to work */ - if( creatorp(this_player()) ) return "Sorry, coders don't get salaries here!"; currs = (string *)this_player()->GetCurrencies(); currs = filter(currs, (: this_player()->GetCurrency($1) > 0 :)); if( !currs || !sizeof(currs) ) { ! write("You are broke."); ! say(this_player()->GetName()+" comes up with empty pockets."); ! return 1; } say(this_player()->GetName()+" fishes through "+ possessive(this_player())+" pockets examining some money."); message("my_action", "In your pockets you find "+ ((sizeof(currs) > 1) ? "these currencies: " : "only: "), this_player()); for(borg = "", i=0, tmp = sizeof(currs); iGetCurrency(currs[i]))+" "+currs[i]); ! if(i == tmp-1) borg +=(".\n"); ! else if(tmp > 2 && i == tmp-2) borg += (", and "); ! else if(tmp == 2) borg +=(" and "); ! else borg +=(", "); } message("my_action", borg, this_player()); return 1; --- 14,36 ---- int i, tmp; if(str) return 0; /* to allow the wiz command to work */ currs = (string *)this_player()->GetCurrencies(); currs = filter(currs, (: this_player()->GetCurrency($1) > 0 :)); if( !currs || !sizeof(currs) ) { ! write("You are broke."); ! say(this_player()->GetName()+" comes up with empty pockets."); ! return 1; } say(this_player()->GetName()+" fishes through "+ possessive(this_player())+" pockets examining some money."); message("my_action", "In your pockets you find "+ ((sizeof(currs) > 1) ? "these currencies: " : "only: "), this_player()); for(borg = "", i=0, tmp = sizeof(currs); iGetCurrency(currs[i]))+" "+currs[i]); ! if(i == tmp-1) borg +=(".\n"); ! else if(tmp > 2 && i == tmp-2) borg += (", and "); ! else if(tmp == 2) borg +=(" and "); ! else borg +=(", "); } message("my_action", borg, this_player()); return 1; diff -c -r --new-file ds1.1/lib/cmds/players/mudlist.c ds2.1/lib/cmds/players/mudlist.c *** ds1.1/lib/cmds/players/mudlist.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/mudlist.c Tue Jul 11 18:30:58 2006 *************** *** 14,19 **** --- 14,20 ---- string *list; mapping borg; string mud; + int all = 0; if( str && str != "" && strlen(str) > 3 ) { mapping tmp; *************** *** 28,42 **** int x, y, z; switch(opt) { ! case "m": ! x = 5; ! break; ! case "d": ! x = 7; ! break; ! case "n": ! x = 0; ! break; } tmpstr = (x ? info[x] : mud); z = strlen(str = replace_string(lower_case(str), " ", "")); --- 29,46 ---- int x, y, z; switch(opt) { ! case "a": ! all = 1; ! break; ! case "m": ! x = 5; ! break; ! case "d": ! x = 7; ! break; ! case "n": ! x = 0; ! break; } tmpstr = (x ? info[x] : mud); z = strlen(str = replace_string(lower_case(str), " ", "")); *************** *** 46,58 **** break; } else if( y > z && tmpstr[0..z-1] == str && info[0] == -1 ) ! borg[mud] = info; } } else { borg = ([ ]); foreach( mud, info in (mapping)INTERMUD_D->GetMudList() ) ! if( info[0] == -1 ) borg[mud] = info; } if( !sizeof(borg) ) { message("system", "No MUDs match your query.", this_player()); --- 50,62 ---- break; } else if( y > z && tmpstr[0..z-1] == str && info[0] == -1 ) ! borg[mud] = info; } } else { borg = ([ ]); foreach( mud, info in (mapping)INTERMUD_D->GetMudList() ) ! if( all == 1 || info[0] == -1 ) borg[mud] = info; } if( !sizeof(borg) ) { message("system", "No MUDs match your query.", this_player()); *************** *** 65,73 **** mud = keys(borg)[0]; msg = "\nDetailed information on %^GREEN%^" + mud + "%^RESET%^:\n"; msg += sprintf("MUD Type: %:-6s Server: %:-20s Library: %s\n", ! borg[mud][8], borg[mud][7], borg[mud][5]); msg += "Status: " + borg[mud][9] + "\nAdmin email: " + ! borg[mud][10] + "\n"; msg += "Services: "; foreach(svc, val in borg[mud][11]) { if( val == 1 ) { --- 69,77 ---- mud = keys(borg)[0]; msg = "\nDetailed information on %^GREEN%^" + mud + "%^RESET%^:\n"; msg += sprintf("MUD Type: %:-6s Server: %:-20s Library: %s\n", ! borg[mud][8], borg[mud][7], borg[mud][5]); msg += "Status: " + borg[mud][9] + "\nAdmin email: " + ! borg[mud][10] + "\n"; msg += "Services: "; foreach(svc, val in borg[mud][11]) { if( val == 1 ) { *************** *** 81,103 **** msg += "\nHost: " + borg[mud][1] + "\n"; msg += "Telnet port: " + borg[mud][2] + "\n"; if( borg[mud][11]["amcp"] ) ! msg += "AMCP version: " + borg[mud][11]["amcp"] + "\n"; if( borg[mud][11]["http"] ) ! msg += "HTTP port (World Wide Web): " + borg[mud][11]["http"]+"\n"; if( borg[mud][11]["ftp"] ) ! msg += "FTP port (File Transfer): " + borg[mud][11]["ftp"] + "\n"; if( borg[mud][11]["rcp"] ) ! msg += "RCP port (Remote Creator): " + borg[mud][11]["rcp"] + "\n"; message("info", msg, this_player()); return 1; } list = ({}); foreach(mud, info in borg) ! list += ({ sprintf("%:-15s %:-6s %:-15s %:-18s %s %d", ! mud, info[8], info[7], info[5], info[1], info[2]) }); list = sort_array(list, 1); ! list = ({ mud_name() + " recognizes " + consolidate(sizeof(borg), "a mud")+ ! " matching your query: ", "" }) + list; this_player()->eventPage(list); return 1; } --- 85,107 ---- msg += "\nHost: " + borg[mud][1] + "\n"; msg += "Telnet port: " + borg[mud][2] + "\n"; if( borg[mud][11]["amcp"] ) ! msg += "AMCP version: " + borg[mud][11]["amcp"] + "\n"; if( borg[mud][11]["http"] ) ! msg += "HTTP port (World Wide Web): " + borg[mud][11]["http"]+"\n"; if( borg[mud][11]["ftp"] ) ! msg += "FTP port (File Transfer): " + borg[mud][11]["ftp"] + "\n"; if( borg[mud][11]["rcp"] ) ! msg += "RCP port (Remote Creator): " + borg[mud][11]["rcp"] + "\n"; message("info", msg, this_player()); return 1; } list = ({}); foreach(mud, info in borg) ! list += ({ sprintf("%:-15s %:-6s %:-15s %:-18s %s %d", ! replace_string(mud,"%^","%%^^"), info[8], info[7], info[5], info[1], info[2]) }); list = sort_array(list, 1); ! list = ({ replace_string(mud_name(),"%^","%%^^") + " recognizes " + consolidate(sizeof(borg), "a mud")+ ! " matching your query: ", "" }) + list; this_player()->eventPage(list); return 1; } *************** *** 110,127 **** void help() { message("help", "Syntax: \n" ! " \n\n" ! "Without any arguments, it gives a full listing of all muds " ! "with which this mud is capable of communication through " ! "tell, mail, finger, rwho, and other intermud services. " ! "With arguments, requires one and only one option " ! "which must be one of the following:\n" ! "\t-d [driver]: List only muds using the named driver\n" ! "\t-m [mudlib]: List only muds using the named mudlib\n" ! "\t-n [mudname]: List only the muds with the name given\n\n" ! "Note that the argument need not be complete, for example:\n" ! "\t mudlist -n idea\n" ! "will list IdeaExchange as well as any other mud whose name " ! "begins with the string \"idea\".\n\n" ! "See also: finger, mail, rwho, tell", this_player()); } --- 114,131 ---- void help() { message("help", "Syntax: \n" ! " \n\n" ! "Without any arguments, it gives a full listing of all muds " ! "with which this mud is capable of communication through " ! "tell, mail, finger, rwho, and other intermud services. " ! "With arguments, requires one and only one option " ! "which must be one of the following:\n" ! "\t-d [driver]: List only muds using the named driver\n" ! "\t-m [mudlib]: List only muds using the named mudlib\n" ! "\t-n [mudname]: List only the muds with the name given\n\n" ! "Note that the argument need not be complete, for example:\n" ! "\t mudlist -n idea\n" ! "will list IdeaExchange as well as any other mud whose name " ! "begins with the string \"idea\".\n\n" ! "See also: finger, mail, rwho, tell", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/newbie.c ds2.1/lib/cmds/players/newbie.c *** ds1.1/lib/cmds/players/newbie.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/newbie.c Wed Jul 12 13:29:17 2006 *************** *** 0 **** --- 1,18 ---- + #include + + inherit LIB_DAEMON; + + int eventNoob(){ + write("%^RED%^WHAT A NEW PLAYER SHOULD KNOW\n%^RESET%^"); + this_player()->eventPage("/doc/help/players/handbook"); + return 1; + } + + mixed cmd(string str) { + return eventNoob(); + } + + void help() { + eventNoob(); + } + diff -c -r --new-file ds1.1/lib/cmds/players/nextreboot.c ds2.1/lib/cmds/players/nextreboot.c *** ds1.1/lib/cmds/players/nextreboot.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/players/nextreboot.c Wed Jul 5 00:01:03 2006 *************** *** 4,29 **** */ #include #include inherit LIB_DAEMON; ! mixed cmd(string str) { ! string tzone; ! int x; x = (int)EVENTS_D->GetRebootInterval() * 3600; x = (time() - uptime()) + x; ! if( tzone = (string)this_player()->GetTimeZone() ) ! x += (int)TIME_D->GetOffset(tzone) * 3600; ! else tzone = "CST"; ! str = tzone + " " + ctime(x); ! message("system", "The next reboot will occur " + str + ".",this_player()); return 1; } string GetHelp(string str) { return ("Syntax: \n\n" ! "Tells you when the next regularly scheduled reboot for " + ! mud_name() + " will occur."); } --- 4,35 ---- */ #include + #include #include inherit LIB_DAEMON; ! mixed cmd(string form) { ! string str; ! int x, offset; ! ! offset = (int)TIME_D->GetOffset(local_time()[9]); ! offset += EXTRA_TIME_OFFSET; x = (int)EVENTS_D->GetRebootInterval() * 3600; x = (time() - uptime()) + x; ! if(query_os_type() != "windows" ) ! x += offset * 3600; ! str = query_tz()+ " " + ctime(x); ! message("system", "Current "+query_tz()+" system time is "+timestamp(), ! this_player()); ! if(form && form == "string") return "The next reboot will occur " + str + "."; ! else message("system", "The next reboot will occur " + str + ".",this_player()); return 1; } string GetHelp(string str) { return ("Syntax: \n\n" ! "Tells you when the next regularly scheduled reboot for " + ! mud_name() + " will occur."); } diff -c -r --new-file ds1.1/lib/cmds/players/plugh.c ds2.1/lib/cmds/players/plugh.c *** ds1.1/lib/cmds/players/plugh.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/plugh.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,11 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + if(!creatorp(this_player())) write("Nothing happens."); + else tell_room(environment(this_player()),"A hollow voice says: \"%^CYAN%^Xyzzy.%^RESET%^\""); + return 1; + } + + diff -c -r --new-file ds1.1/lib/cmds/players/posting.c ds2.1/lib/cmds/players/posting.c *** ds1.1/lib/cmds/players/posting.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/posting.c Wed Jul 5 00:01:03 2006 *************** *** 1,32 **** // Command _posting.c // Written by Hanse@Dead Souls 6/21/93 ! #include inherit LIB_DAEMON; ! int cmd(string str) { ! object *list; ! int i; ! ! if(str) return 0; ! list=users(); ! write("\nList of users in various editors:\n"); ! for(i=0;iGetInvis() && list[i]->GetKeyName()) ! if(present("mailer", list[i])) ! printf("%s - In mailer.\n", ! arrange_string( (string)list[i]->GetName(), 20)); ! else if(in_edit(list[i]) || in_input(list[i])) ! printf("%s - Editing.\n", ! arrange_string( (string)list[i]->GetName(), 20)); ! return 1; } ! void help() { ! write(@END Syntax: posting Displays if a user is in editor, posting on a bulletin board, or in the mailer. END ! ); } --- 1,32 ---- // Command _posting.c // Written by Hanse@Dead Souls 6/21/93 ! #include inherit LIB_DAEMON; ! int cmd(string str) { ! object *list; ! int i; ! ! if(str) return 0; ! list=users(); ! write("\nList of users in various editors:\n"); ! for(i=0;iGetInvis() && list[i]->GetKeyName()) ! if(present("mailer", list[i])) ! printf("%s - In mailer.\n", ! arrange_string( (string)list[i]->GetName(), 20)); ! else if(in_edit(list[i]) || in_input(list[i])) ! printf("%s - Editing.\n", ! arrange_string( (string)list[i]->GetName(), 20)); ! return 1; } ! void help() { ! write(@END Syntax: posting Displays if a user is in editor, posting on a bulletin board, or in the mailer. END ! ); } diff -c -r --new-file ds1.1/lib/cmds/players/quests.c ds2.1/lib/cmds/players/quests.c *** ds1.1/lib/cmds/players/quests.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/quests.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,45 ---- + #include + + inherit LIB_DAEMON; + + mixed cmd(string str) { + string ret; + object dude; + + if(str && !creatorp(this_player()) ) { + if(!find_player(str) || find_player(str) != this_player()){ + write("You can only get quest information about yourself."); + return 1; + } + } + if(str && !find_player(str)){ + write("That player isn't logged on."); + return 1; + } + if(str) dude = find_player(str); + else dude = this_player(); + if(!sizeof(dude->GetQuests())){ + if(dude == this_player()) write("You have completed no quests."); + else write(dude->GetName()+" has completed no quests."); + return 1; + } + + if(dude == this_player()) ret = "You have completed the following quests:\n"; + else ret = dude->GetName()+" has completed the following quests:\n"; + + ret += "----------------------------------------\n"; + + foreach(string *quests in dude->GetQuests()){ + ret += quests[1] + "\n"; + } + write(ret); + return 1; + } + + void help() { + message("help", + "Syntax: quests\n\n" + "This command lists the quests you have completed.\n\n", + this_player() ); + } + diff -c -r --new-file ds1.1/lib/cmds/players/rwho.c ds2.1/lib/cmds/players/rwho.c *** ds1.1/lib/cmds/players/rwho.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/players/rwho.c Wed Jul 5 00:01:03 2006 *************** *** 12,18 **** mixed cmd(string str) { if( !str ) return "Get a remote who from where?"; if( !(str = (string)INTERMUD_D->GetMudName(str)) ) ! return mud_name() + " is not aware of such a place."; SERVICES_D->eventSendWhoRequest(str); message("system", "Remote who query sent to " + str + ".", this_player()); return 1; --- 12,18 ---- mixed cmd(string str) { if( !str ) return "Get a remote who from where?"; if( !(str = (string)INTERMUD_D->GetMudName(str)) ) ! return mud_name() + " is not aware of such a place."; SERVICES_D->eventSendWhoRequest(str); message("system", "Remote who query sent to " + str + ".", this_player()); return 1; diff -c -r --new-file ds1.1/lib/cmds/players/save.c ds2.1/lib/cmds/players/save.c *** ds1.1/lib/cmds/players/save.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/save.c Wed Jul 5 00:01:03 2006 *************** *** 21,31 **** int help() { ! message("help", "Command: save\nSyntax: save\n\nThis command saves the" ! " present status of your character to disk. This is important as" ! " it is this file that will be used to set your character back " ! "up if the mud should crash. Your character is automatically " ! "saved if you quit.", this_player()); ! return 1; } /* EOF */ --- 21,31 ---- int help() { ! message("help", "Command: save\nSyntax: save\n\nThis command saves the" ! " present status of your character to disk. This is important as" ! " it is this file that will be used to set your character back " ! "up if the mud should crash. Your character is automatically " ! "saved if you quit.", this_player()); ! return 1; } /* EOF */ diff -c -r --new-file ds1.1/lib/cmds/players/score.c ds2.1/lib/cmds/players/score.c *** ds1.1/lib/cmds/players/score.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/score.c Wed Jul 5 00:01:03 2006 *************** *** 3,88 **** * Displays a list of score and related info * created by Blitz@Dead Souls */ ! #include ! inherit LIB_DAEMON; inherit LIB_HELP; ! mixed eventScore(); ! static void create() { ! daemon::create(); ! SetNoClean(1); ! SetHelp("Syntax: score\n\n" ! "Displays information about your character.\n\n" ! "See also: status\n"); } ! static string *FoodDegree = ({ "could eat a horse right now!", "could eat plenty more.", ! "could eat some more.", "are partially hungry.", ! "are feeling full.", "feel quite full." }); ! static string *DrunkDegree = ! ({ "sober", "tipsy", "drunk", "blitzed", ! "smashed out of your gord", "FUBAR" }); ! static string *DrinkDegree = ({ "parched", "extremely thirsty", "very thirsty", "thirsty", ! "somewhat thirsty", "not thirsty" }); ! mixed cmd(string unused) { ! if( creatorp(this_player()) ) ! return "Creators have no score, get a life."; ! eventScore(); ! return 1; } ! mixed eventScore() { ! string *str; ! int birth, age, x, y, z; ! ! str = ({ "You are "+(string)this_player()->GetShort() + " (" + ! (string)this_player()->GetMoralityDescription() + ")." }); ! str += ({ sprintf("You are a level %d %s%s %s.", ! (int)this_player()->GetLevel(), ! ( (int)this_player()->GetUndead() ? "undead " : ""), ! capitalize((string)this_player()->GetRace() || "nothing"), ! capitalize((string)this_player()->GetClass() || "commoner")) }); ! str += ({ "Your native town is "+(string)this_player()->GetTown()+", and " ! "you are " + ((string)this_player()->GetReligion() || ! "agnostic") + " in faith." }); ! str += ({ sprintf("You've solved %s, and have %s.", ! consolidate(sizeof((string *)this_player()->GetQuests()), ! "one quest"), ! consolidate(sizeof((string *)this_player()->GetTitles()), ! "one title") ) }); ! birth = (int)this_player()->GetBirth(); ! age = ( query_year(time()) - query_year(birth) ); ! str += ({ sprintf("You were born on the %d%s day of %s, year %d. " ! "(%d years old)", query_date(birth), ordinal(query_date(birth)), ! query_month(birth), query_year(birth), age) }); ! if( x = (int)this_player()->GetTrainingPoints() < 1 ) { ! y = (int)this_player()->GetLevel() + 1 + (x / -4); ! str += ({ "Training points await you at level " + y + "." }); ! } ! else str += ({ "You have " + consolidate( ! (int)this_player()->GetTrainingPoints(), ! "one training point") + "." }); ! if( (int)this_player()->GetWimpy() ) ! str += ({ "You are feeling wimpy." }); else ! str += ({ "You are feeling brave." }); ! if( (int)this_player()->GetPoison() > 0 ) ! str += ({ "You are poisoned." }); ! x = (int)this_player()->GetFood() / 17; ! if( x > sizeof(FoodDegree) - 1 ) x = (sizeof(FoodDegree) - 1); ! y = (int)this_player()->GetDrink() / 17; ! if( y > sizeof(DrinkDegree) - 1 ) y = (sizeof(DrinkDegree) - 1); ! z = (int)this_player()->GetAlcohol() / 17; ! if( z > sizeof(DrunkDegree) - 1 ) z = (sizeof(DrunkDegree) - 1); ! str += ({ "You "+FoodDegree[x] }); ! str += ({ sprintf("You are %s and %s.", DrinkDegree[y], DrunkDegree[z]) }); ! this_player()->eventPage(str, "info"); ! return 1; } --- 3,86 ---- * Displays a list of score and related info * created by Blitz@Dead Souls */ ! #include ! inherit LIB_DAEMON; inherit LIB_HELP; ! mixed eventScore(); ! static void create() { ! daemon::create(); ! SetNoClean(1); ! SetHelp("Syntax: score\n\n" ! "Displays information about your character.\n\n" ! "See also: status\n"); } ! static string *FoodDegree = ({ "could eat a horse right now!", "could eat plenty more.", ! "could eat some more.", "are partially hungry.", ! "are feeling full.", "feel quite full." }); ! static string *DrunkDegree = ! ({ "you are sober", "you are tipsy", "you are drunk", "you are blitzed", ! "you are smashed out of your gord", "you are FUBAR" }); ! static string *DrinkDegree = ({ "parched", "extremely thirsty", "very thirsty", "thirsty", ! "somewhat thirsty", "not thirsty" }); ! mixed cmd(string unused) { ! eventScore(); ! return 1; } ! mixed eventScore() { ! string *str; ! int birth, age, x, y, z; ! ! str = ({ "You are "+(string)this_player()->GetShort() + " (" + ! (string)this_player()->GetMoralityDescription() + ")." }); ! str += ({ sprintf("You are a level %d %s%s %s.", ! (int)this_player()->GetLevel(), ! ( (int)this_player()->GetUndead() ? "undead " : ""), ! capitalize((string)this_player()->GetRace() || "nothing"), ! capitalize((string)this_player()->GetClass() || "commoner")) }); ! str += ({ "Your native town is "+(string)this_player()->GetTown()+", and " ! "you are " + ((string)this_player()->GetReligion() || ! "agnostic") + " in faith." }); ! str += ({ sprintf("You've solved %s, and have %s.", ! consolidate(sizeof((string *)this_player()->GetQuests()), ! "one quest"), ! consolidate(sizeof((string *)this_player()->GetTitles()), ! "one title") ) }); ! birth = (int)this_player()->GetBirth(); ! age = ( query_year(time()) - query_year(birth) ); ! str += ({ sprintf("You were born on the %d%s day of %s, year %d. " ! "(%d years old)", query_date(birth), ordinal(query_date(birth)), ! query_month(birth), query_year(birth), age) }); ! if( x = (int)this_player()->GetTrainingPoints() < 1 ) { ! y = (int)this_player()->GetLevel() + 1 + (x / -4); ! str += ({ "Training points await you at level " + y + "." }); ! } ! else str += ({ "You have " + consolidate( ! (int)this_player()->GetTrainingPoints(), ! "one training point") + "." }); ! if( (int)this_player()->GetWimpy() ) ! str += ({ "You are feeling wimpy." }); else ! str += ({ "You are feeling brave." }); ! if( (int)this_player()->GetPoison() > 0 ) ! str += ({ "You are poisoned." }); ! x = (int)this_player()->GetFood() / 17; ! if( x > sizeof(FoodDegree) - 1 ) x = (sizeof(FoodDegree) - 1); ! y = (int)this_player()->GetDrink() / 17; ! if( y > sizeof(DrinkDegree) - 1 ) y = (sizeof(DrinkDegree) - 1); ! z = (int)this_player()->GetAlcohol() / 17; ! if( z > sizeof(DrunkDegree) - 1 ) z = (sizeof(DrunkDegree) - 1); ! str += ({ "You "+FoodDegree[x] }); ! str += ({ sprintf("You are %s and %s.", DrinkDegree[y], DrunkDegree[z]) }); ! this_player()->eventPage(str, "info"); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/players/screen.c ds2.1/lib/cmds/players/screen.c *** ds1.1/lib/cmds/players/screen.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/screen.c Wed Jul 5 00:01:03 2006 *************** *** 11,21 **** mixed cmd(string args) { int *screen; int h, w; if( args == "" || !args ) ! return "You need to specify both width and height."; if( sscanf(args, "%d %d", w, h) != 2 ) ! return "You need to specify both width and height."; this_player()->SetScreen(w, h); message("system", "Screen set to " + w + " by " + h + ".", this_player()); return 1; --- 11,24 ---- mixed cmd(string args) { int *screen; int h, w; + string chide = "You need to specify both width and height.\n"; + string ret = "Your current settings are: "+ this_player()->GetScreen()[0]; + ret += " "+ this_player()->GetScreen()[1]; if( args == "" || !args ) ! return chide + ret; if( sscanf(args, "%d %d", w, h) != 2 ) ! return chide + ret; this_player()->SetScreen(w, h); message("system", "Screen set to " + w + " by " + h + ".", this_player()); return 1; *************** *** 23,29 **** void help() { message("help", "Syntax: \n\n" ! "Sets the dimensions of your computer screen so that " + ! mud_name() + " knows how to send information to your screen.\n\n" ! "See also: brief, terminal", this_player()); } --- 26,32 ---- void help() { message("help", "Syntax: \n\n" ! "Sets the dimensions of your computer screen so that " + ! mud_name() + " knows how to send information to your screen.\n\n" ! "See also: brief, terminal", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/skills.c ds2.1/lib/cmds/players/skills.c *** ds1.1/lib/cmds/players/skills.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/skills.c Wed Jul 5 00:01:03 2006 *************** *** 5,63 **** * - Moved map function to GetLine for readability, added a max skill * level display for each skill, grouped in classes. (Blitz 960122/0404) */ ! #include ! inherit LIB_DAEMON; ! string GetLine(string skill) { int x, max; mapping mp = (mapping)this_player()->GetSkill(skill); ! if( !sizeof(mp) ) return 0; x = to_int(percent(mp["points"], ! (int)this_player()->GetMaxSkillPoints(skill, mp["level"]))); max = ( mp["class"] == 1 ? 2 : 1 ) + (int)this_player()->GetLevel(); max *= 2; if( max < mp["level"] ) max = mp["level"]; return sprintf("%:-20s: %:-6s (%d%%)", skill, ! (mp["level"] + "/" + max), x); } ! mixed cmd(string args) { string *skills, *primes, *secs; string ret, tmp; int x, scr; ! ! if( creatorp(this_player()) ) { ! message("system", "Creators have no skills, get a life.", ! this_player()); ! return 1; ! } ret = "You are " +(string)this_player()->GetShort() + ", level " + ! (int)this_player()->GetLevel(); if( (tmp = (string)this_player()->GetClass()) ) ! ret += " " + capitalize(tmp); else ret += " Drifter"; ret += " (" + (string)this_player()->GetRace() + ")\n"; scr = ((int *)this_player()->GetScreen())[0]; ! skills = sort_array((string *)this_player()->GetSkills(), 1); if( !sizeof(skills) ) { ! ret += "You are without skills.\n"; ! this_player()->eventPrint(ret); ! return 1; } skills = skills - (primes = filter(skills, ! (: this_player()->GetSkillClass($1) == 1 :))); skills = skills - (secs = filter(skills, ! (: this_player()->GetSkillClass($1) == 2 :))); skills = map(skills, (: GetLine :)); primes = map(primes, (: GetLine :)); secs = map(secs, (: GetLine :)); foreach(mixed sarray in ({ primes, secs, skills }) ) { ! int y, i = sizeof(sarray); ! while(i--) if( (y = strlen(sarray[i])) > x ) x = y; } x = scr/(x+2); ret += "%^BOLD%^%^BLUE%^Primary skills:%^RESET%^\n"; --- 5,58 ---- * - Moved map function to GetLine for readability, added a max skill * level display for each skill, grouped in classes. (Blitz 960122/0404) */ ! #include ! inherit LIB_DAEMON; ! string GetLine(string skill) { int x, max; mapping mp = (mapping)this_player()->GetSkill(skill); ! if( !sizeof(mp) ) return 0; x = to_int(percent(mp["points"], ! (int)this_player()->GetMaxSkillPoints(skill, mp["level"]))); max = ( mp["class"] == 1 ? 2 : 1 ) + (int)this_player()->GetLevel(); max *= 2; if( max < mp["level"] ) max = mp["level"]; return sprintf("%:-20s: %:-6s (%d%%)", skill, ! (mp["level"] + "/" + max), x); } ! mixed cmd(string args) { string *skills, *primes, *secs; string ret, tmp; int x, scr; ! ret = "You are " +(string)this_player()->GetShort() + ", level " + ! (int)this_player()->GetLevel(); if( (tmp = (string)this_player()->GetClass()) ) ! ret += " " + capitalize(tmp); else ret += " Drifter"; ret += " (" + (string)this_player()->GetRace() + ")\n"; scr = ((int *)this_player()->GetScreen())[0]; ! skills = sort_array((string *)this_player()->GetSkills(), 1); if( !sizeof(skills) ) { ! ret += "You are without skills.\n"; ! this_player()->eventPrint(ret); ! return 1; } skills = skills - (primes = filter(skills, ! (: this_player()->GetSkillClass($1) == 1 :))); skills = skills - (secs = filter(skills, ! (: this_player()->GetSkillClass($1) == 2 :))); skills = map(skills, (: GetLine :)); primes = map(primes, (: GetLine :)); secs = map(secs, (: GetLine :)); foreach(mixed sarray in ({ primes, secs, skills }) ) { ! int y, i = sizeof(sarray); ! while(i--) if( (y = strlen(sarray[i])) > x ) x = y; } x = scr/(x+2); ret += "%^BOLD%^%^BLUE%^Primary skills:%^RESET%^\n"; *************** *** 69,78 **** this_player()->eventPage(explode(ret, "\n")); return 1; } ! string GetHelp(string foo) { return "Syntax: \n\n" ! "Lists all of your skills as well as how skilled you are " ! "at the skill in question.\n\n" ! "See also: stats, status"; } --- 64,73 ---- this_player()->eventPage(explode(ret, "\n")); return 1; } ! string GetHelp(string foo) { return "Syntax: \n\n" ! "Lists all of your skills as well as how skilled you are " ! "at the skill in question.\n\n" ! "See also: stats, status"; } diff -c -r --new-file ds1.1/lib/cmds/players/spells.c ds2.1/lib/cmds/players/spells.c *** ds1.1/lib/cmds/players/spells.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/players/spells.c Wed Jul 5 00:01:03 2006 *************** *** 14,24 **** string array spells = ({}); string tmp; int len; ! ! if( creatorp(who) ) { ! who->eventPrint("Creators know no spells."); ! return 1; ! } tmp = "You know the following spells:\n"; foreach(string spell, int val in who->GetSpellBook()) { spells += ({ sprintf("%:-20s: %:-3d%%", spell, val) }); --- 14,20 ---- string array spells = ({}); string tmp; int len; ! tmp = "You know the following spells:\n"; foreach(string spell, int val in who->GetSpellBook()) { spells += ({ sprintf("%:-20s: %:-3d%%", spell, val) }); *************** *** 29,35 **** else { foreach(string spell in spells) { int i = strlen(spell); ! if( i > len ) { len = i; } --- 25,31 ---- else { foreach(string spell in spells) { int i = strlen(spell); ! if( i > len ) { len = i; } *************** *** 43,49 **** string GetHelp() { return ("Syntax: \n\n" ! "Lists all of your spells in your spell book with your " ! "proficiency in each spell.\n\n" ! "See also: skills, stats, status"); } --- 39,45 ---- string GetHelp() { return ("Syntax: \n\n" ! "Lists all of your spells in your spell book with your " ! "proficiency in each spell.\n\n" ! "See also: skills, stats, status"); } diff -c -r --new-file ds1.1/lib/cmds/players/stat.c ds2.1/lib/cmds/players/stat.c *** ds1.1/lib/cmds/players/stat.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/stat.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,117 ---- + /* /cmds/creator/stat.c + * from the Dead Souls LPC Library + * a command to view something's stats + * created by Descartes of Borg 950409 + */ + + #include + + inherit LIB_DAEMON; + + mixed cmd(string args) { + string *lines, *arr, *limbs; + object ob; + string tmp1, tmp2; + int i, x, y, cols; + + if( args == "" || !args || args == "me" ) args = this_player()->GetKeyName(); + else if(args && !creatorp(this_player())) { + write("You can only stat yourself."); + return 1; + } + + if( !(ob = present(args, environment(this_player()))) ) + if( !(ob = find_player(convert_name(args))) && + !(ob = find_living(lower_case(args))) ) + return capitalize(args) + " is nowhere to be found."; + if(!living(ob)) return capitalize(args) + " is not alive."; + cols = ((int *)this_player()->GetScreen())[0]; + tmp1 = (string)ob->GetCapName() + " aka " + (string)ob->GetShort() + + ", level " + (int)ob->GetLevel() + " " + (string)ob->GetGender(); + if( !(tmp2 = (string)ob->GetRace()) ) tmp2 = "blob"; + tmp1 += " " + tmp2; + if( !(tmp2 = (string)ob->GetClass()) || !stringp(tmp2)) tmp2 = "drifter"; + tmp1 += " " + capitalize(tmp2); + if( tmp2 = (string)ob->GetSpouse() ) + tmp1 += " (spouse: " + tmp2 + ")"; + lines = ({ center(tmp1, cols) }); + if( (int)ob->GetUndead() ) tmp1 = "%^BOLD%^RED%^UNDEAD%^RESET%^"; + else tmp1 = "%^BOLD%^GREEN%^Alive%^RESET%^"; + if( (int)ob->GetSleeping() ) tmp1 += " / Sleeping"; + else tmp1 += " / Awake"; + if( (int)ob->GetParalyzed() ) tmp1 += " / Paralyzed"; + lines += ({ center(tmp1, cols), "" }); + lines += ({ center("Health: " +(int)ob->GetHealthPoints() + "/"+ + (int)ob->GetMaxHealthPoints() + " Magic: " + + (int)ob->GetMagicPoints() + "/" + + (int)ob->GetMaxMagicPoints() + " Stamina: " + + (int)ob->GetStaminaPoints() + "/" + + to_int((float)ob->GetMaxStaminaPoints()) + " Carry: " + + (int)ob->GetCarriedMass() + "/" + + (int)ob->GetMaxCarry(), cols) }); + lines += ({ center("Food: " + (int)ob->GetFood() + " " + + "Drink: " + (int)ob->GetDrink() + " " + + "Alcohol: " + (int)ob->GetAlcohol() + " " + + "Caffeine: " + (int)ob->GetCaffeine() + " " + + "Poison: " + (int)ob->GetPoison() + " ", cols) }); + lines += ({ "\n" }) ; + lines += ({ center("Training Points: " + (int)ob->GetTrainingPoints() + + " " + + "Quest Points: "+ (int)ob->GetQuestPoints() + + " " + + //Fix below courtesy of Jonez + "Experience Points: "+ (int)ob->GetExperiencePoints()),cols + }); + lines += ({ "", "Limbs:" }); + limbs = (string *)ob->GetWieldingLimbs(); + if(ob && !ob->GetGhost()) arr = map((string *)ob->GetLimbs(), + (: sprintf("%:-14s%s (%d) %d/%d", $1, + ((member_array($1, $(limbs)) == -1) ? " " : "*"), + (int)($(ob))->GetLimbClass($1), + (int)($(ob))->GetHealthPoints($1), + (int)($(ob))->GetMaxHealthPoints($1)) :)); + i = sizeof(arr); + while(i--) if( (y = strlen(arr[i])) > x ) x = y; + x = cols/(x+2); + lines += explode(format_page(arr, x), "\n") + ({ "", "Skills:" }); + arr = map((string *)ob->GetSkills(), + function(string skill, object who) { + mapping mp = (mapping)who->GetSkill(skill); + int x, max; + x = to_int(percent(mp["points"], + (int)who->GetMaxSkillPoints(skill, mp["level"]))); + max = ( mp["class"] == 1 ? 2 : 1 ) + who->GetLevel(); + max *= 2; + if( max < mp["level"] ) max = mp["level"]; + return sprintf("%:-18s (%d) %:2d%% - %d/%d", + skill, mp["class"], x, mp["level"], max); + }, ob); + i = sizeof(arr); + while(i--) if( (y = strlen(arr[i])) > x ) x = y; + x = cols/(x+2); + lines += explode(format_page(arr, x), "\n") + ({ "", "Stats:" }); + arr = map((string *)ob->GetStats(), + (: sprintf("%:-12s (%d) %d/%d", $1, + (int)($(ob))->GetStatClass($1), + (int)($(ob))->GetStatLevel($1), + (int)($(ob))->GetBaseStatLevel($1)) :)); + i = sizeof(arr); + x = 0; + while(i--) if( (y = strlen(arr[i])) > x ) x = y; + x =cols/(x+2); + lines += explode(format_page(arr, x), "\n"); + lines += ({ "", (string)ob->GetName()+" has amassed a net worth of " + + ( (int)ob->GetNetWorth("gold") ) + " gold."}); + arr = filter( map((string *)ob->GetCurrencies(), + (: ($(ob))->GetCurrency($1) && + sprintf("%d %s", ($(ob))->GetCurrency($1), $1) :)), + (: $1 :)); + lines += ({ "Money on hand: "+implode(arr, ", ") }); + this_player()->eventPage(lines, "system"); + return 1; + } + + string GetHelp(string blah) { + return ("Syntax: stat \n\n" + "Displays statistical information a living object."); + } diff -c -r --new-file ds1.1/lib/cmds/players/stats.c ds2.1/lib/cmds/players/stats.c *** ds1.1/lib/cmds/players/stats.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/stats.c Wed Jul 5 00:01:03 2006 *************** *** 13,32 **** string ret, tmp; int i, x, y; - if( creatorp(this_player()) ) { - message("system", "Creators have no stats, get a life.", - this_player()); - return 1; - } ret = "You are " +(string)this_player()->GetShort() + ", level " + ! (int)this_player()->GetLevel(); if( (tmp = (string)this_player()->GetClass()) ) ! ret += " " + capitalize(tmp); else ret += " Drifter"; ret += " (" + (string)this_player()->GetRace() + ")\n"; stats = map((string)this_player()->GetStats(), ! (: sprintf("%:-20s: %:-3d", $1, ! (int)this_player()->GetStatLevel($1)) :)); i = sizeof(stats); while(i--) if( (y = strlen(stats[i])) > x ) x = y; x = ((int *)this_player()->GetScreen())[0]/(x+2); --- 13,27 ---- string ret, tmp; int i, x, y; ret = "You are " +(string)this_player()->GetShort() + ", level " + ! (int)this_player()->GetLevel(); if( (tmp = (string)this_player()->GetClass()) ) ! ret += " " + capitalize(tmp); else ret += " Drifter"; ret += " (" + (string)this_player()->GetRace() + ")\n"; stats = map((string)this_player()->GetStats(), ! (: sprintf("%:-20s: %:-3d", $1, ! (int)this_player()->GetStatLevel($1)) :)); i = sizeof(stats); while(i--) if( (y = strlen(stats[i])) > x ) x = y; x = ((int *)this_player()->GetScreen())[0]/(x+2); *************** *** 37,43 **** void help() { message("help", "Syntax: \n\n" ! "Lists all of your stats as well as how skilled you are " ! "at the skill in question.\n\n" ! "See also: stats, status", this_player()); } --- 32,38 ---- void help() { message("help", "Syntax: \n\n" ! "Lists all of your stats as well as how skilled you are " ! "at the skill in question.\n\n" ! "See also: stats, status", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/status.c ds2.1/lib/cmds/players/status.c *** ds1.1/lib/cmds/players/status.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/cmds/players/status.c Wed Jul 5 00:01:03 2006 *************** *** 12,17 **** void help() { message("help", "Syntax: \n\n" ! "Gives you information about your current physical status.\n\n" ! "See also: money, skills, stats", this_player()); } --- 12,17 ---- void help() { message("help", "Syntax: \n\n" ! "Gives you information about your current physical status.\n\n" ! "See also: money, skills, stats", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/terminal.c ds2.1/lib/cmds/players/terminal.c *** ds1.1/lib/cmds/players/terminal.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/cmds/players/terminal.c Wed Jul 5 00:01:03 2006 *************** *** 11,24 **** mixed cmd(string args) { if( !args || args == "" ) return "Set it to what?"; message("system", "Terminal set to " + ! (string)this_player()->SetTerminal(args) + ".", this_player()); return 1; } void help() { message("help", "Syntax: \n\n" ! "Allows you to set your terminal type manually in the " ! "event the MUD does not automatically recognize the proper " ! "setting.\n\n" ! "See also: screen", this_player()); } --- 11,24 ---- mixed cmd(string args) { if( !args || args == "" ) return "Set it to what?"; message("system", "Terminal set to " + ! (string)this_player()->SetTerminal(args) + ".", this_player()); return 1; } void help() { message("help", "Syntax: \n\n" ! "Allows you to set your terminal type manually in the " ! "event the MUD does not automatically recognize the proper " ! "setting.\n\n" ! "See also: screen", this_player()); } diff -c -r --new-file ds1.1/lib/cmds/players/title.c ds2.1/lib/cmds/players/title.c *** ds1.1/lib/cmds/players/title.c Sun Feb 1 21:29:52 1998 --- ds2.1/lib/cmds/players/title.c Wed Jul 5 00:01:03 2006 *************** *** 5,10 **** --- 5,11 ---- */ #include + #include inherit LIB_DAEMON; *************** *** 14,38 **** mixed cmd(string args) { string *titles; ! int i, maxi; ! if( creatorp(this_player()) || avatarp(this_player()) ) { if( !args || args == "" ) return "Change your title to what?"; else args = (string)this_player()->SetShort(args); message("system", "Title changed to: " + args, this_player()); return 1; } if( !(maxi = sizeof(titles = (string *)this_player()->GetTitles())) ) ! return "You are totally unaccomplished."; if( args == "1" || args == "2" ) { ! this_player()->SetTitleLength(to_int(args)); ! this_player()->SetShort("foo"); ! this_player()->eventPrint("Number of titles in your descriptions changed to " + args + "."); ! return 1; } if( maxi == 1 ) { message("system", "You have only one title: " + titles[0], ! this_player()); return 1; } else if( maxi == 2 ) { --- 15,43 ---- mixed cmd(string args) { string *titles; ! int maxi; ! if( creatorp(this_player()) || avatarp(this_player()) ) { if( !args || args == "" ) return "Change your title to what?"; else args = (string)this_player()->SetShort(args); message("system", "Title changed to: " + args, this_player()); + this_player()->save_player((string)this_player()->GetKeyName()); + update("/secure/daemon/finger"); return 1; } if( !(maxi = sizeof(titles = (string *)this_player()->GetTitles())) ) ! return "You are totally unaccomplished."; if( args == "1" || args == "2" ) { ! this_player()->SetTitleLength(to_int(args)); ! this_player()->SetShort("foo"); ! this_player()->eventPrint("Number of titles in your descriptions changed to " + args + "."); ! this_player()->save_player((string)this_player()->GetKeyName()); ! update("/secure/daemon/finger"); ! return 1; } if( maxi == 1 ) { message("system", "You have only one title: " + titles[0], ! this_player()); return 1; } else if( maxi == 2 ) { *************** *** 46,54 **** } this_player()->SetTitles( ({ titles[1], titles[0] }) ); message("system", "Titles reversed.", this_player()); }; message("system", "You have the following titles:\n\t" + ! titles[0] + "\n\t" + titles[1], this_player()); message("prompt", "Do you wish to reverse them? [n] ", this_player()); input_to(f, titles); return 1; --- 51,61 ---- } this_player()->SetTitles( ({ titles[1], titles[0] }) ); message("system", "Titles reversed.", this_player()); + this_player()->save_player((string)this_player()->GetKeyName()); + update("/secure/daemon/finger"); }; message("system", "You have the following titles:\n\t" + ! titles[0] + "\n\t" + titles[1], this_player()); message("prompt", "Do you wish to reverse them? [n] ", this_player()); input_to(f, titles); return 1; *************** *** 62,70 **** message("system", "You have the following titles:", this_player()); for(i=0; iSetTitles(titles); message("system", "Done.", this_player()); + this_player()->save_player((string)this_player()->GetKeyName()); + update("/secure/daemon/finger"); return; } else if( which == "" || !which ) which = "1"; *************** *** 119,140 **** void help() { if( creatorp(this_player()) ) { message("help", "Syntax: \n\n" ! "Allows you to change your title. You must include the " ! "token $N in your title, which will be replaced with your " ! "name as appropriate. For example:\n" ! "\ttitle We are $N of Borg\n" ! "would make my short appear as:\n" ! "\tWe are Descartes of Borg.\n\n", this_player()); } else { message("help", "Syntax: <title>\n\n" ! "Allows you to reorder your titles. Your first two titles " ! "appear in your short description. This command is " ! "interactive, meaning it prompts you for what to do. " ! "hit 'q' at any point to save your changes and exit out of " ! "this command.\nYou can also type (title 1) or (title 2) " ! "to change how many titles appear in your description.", ! this_player() ); } } --- 128,149 ---- void help() { if( creatorp(this_player()) ) { message("help", "Syntax: <title [title]>\n\n" ! "Allows you to change your title. You must include the " ! "token $N in your title, which will be replaced with your " ! "name as appropriate. For example:\n" ! "\ttitle We are $N of Borg\n" ! "would make my short appear as:\n" ! "\tWe are Descartes of Borg.\n\n", this_player()); } else { message("help", "Syntax: <title>\n\n" ! "Allows you to reorder your titles. Your first two titles " ! "appear in your short description. This command is " ! "interactive, meaning it prompts you for what to do. " ! "hit 'q' at any point to save your changes and exit out of " ! "this command.\nYou can also type (title 1) or (title 2) " ! "to change how many titles appear in your description.", ! this_player() ); } } diff -c -r --new-file ds1.1/lib/cmds/players/unmuff.c ds2.1/lib/cmds/players/unmuff.c *** ds1.1/lib/cmds/players/unmuff.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/unmuff.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,26 ---- + #include <lib.h> + + inherit LIB_DAEMON; + + mixed cmd(string str) { + if(!sizeof(this_player()->GetMuffed())) return "You are ignoring no one."; + else if(!str || str == "") return "Please be more specific."; + else { + string *iglist = this_player()->GetMuffed(); + if(member_array(lower_case(str),iglist) == -1) return "You aren't ignoring them."; + iglist -= ({ lower_case(str) }); + this_player()->SetMuffed(iglist); + write("You remove "+capitalize(str)+" from your earmuffed list."); + } + return 1; + } + + void help() { + message("help", + "Syntax: unmuff\n" + " unmuff <name>\n\n" + "This command allows you to stop ignoring channel messages from the name specified.\n" + "See also: earmuff, whomuffed\n\n", + this_player() ); + } + diff -c -r --new-file ds1.1/lib/cmds/players/uptime.c ds2.1/lib/cmds/players/uptime.c *** ds1.1/lib/cmds/players/uptime.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/cmds/players/uptime.c Wed Jul 5 00:01:03 2006 *************** *** 20,42 **** str = mud_name() + " has been up for %^ORANGE%^"; if (x = (tm / WEEK)) { ! str += x + "w "; ! tm -= x * WEEK; } if (x = (tm / DAY)) { ! str += x +"d "; ! tm -= x * DAY; } if (x = (tm / HOUR)) { ! str += x + "h "; ! tm -= x * HOUR; } if (x = (tm / MIN)) { ! str += x + "m "; ! tm -= x * MIN; } if (tm) { ! str += tm + "s "; } str = str[0..<2] + "%^RESET%^."; write(str); --- 20,42 ---- str = mud_name() + " has been up for %^ORANGE%^"; if (x = (tm / WEEK)) { ! str += x + "w "; ! tm -= x * WEEK; } if (x = (tm / DAY)) { ! str += x +"d "; ! tm -= x * DAY; } if (x = (tm / HOUR)) { ! str += x + "h "; ! tm -= x * HOUR; } if (x = (tm / MIN)) { ! str += x + "m "; ! tm -= x * MIN; } if (tm) { ! str += tm + "s "; } str = str[0..<2] + "%^RESET%^."; write(str); diff -c -r --new-file ds1.1/lib/cmds/players/users.c ds2.1/lib/cmds/players/users.c *** ds1.1/lib/cmds/players/users.c Sun Feb 1 21:29:53 1998 --- ds2.1/lib/cmds/players/users.c Wed Jul 5 00:01:03 2006 *************** *** 13,27 **** user_ob = users(); user_name = ({ }); for (i = 0; i < sizeof(user_ob); i++) { ! if( user_ob[i]->GetInvis() ) ! continue; ! name = (string)user_ob[i]->GetKeyName(); ! if (stringp(name)) ! user_name += ({ capitalize(name) }); } user_name = sort_array(user_name, "sort_names"); ! write(format_page(user_name, 4)); ! write(sprintf("Total : %d", sizeof(user_name))); return 1; } --- 13,29 ---- user_ob = users(); user_name = ({ }); for (i = 0; i < sizeof(user_ob); i++) { ! if(user_ob[i]){ ! if( user_ob[i]->GetInvis() ) ! continue; ! name = (string)user_ob[i]->GetKeyName(); ! if (stringp(name)) ! user_name += ({ capitalize(name) }); ! } } user_name = sort_array(user_name, "sort_names"); ! write(format_page(user_name, 4)); ! write(sprintf("Total : %d", sizeof(user_name))); return 1; } *************** *** 37,49 **** int help() { ! write( @EndText Syntax: users Effect: Lists the names of player logged in. A shorter and quicker version of "who" See also: who, where See also: say, tell, class EndText ! ); ! return 1; } --- 39,51 ---- int help() { ! write( @EndText Syntax: users Effect: Lists the names of player logged in. A shorter and quicker version of "who" See also: who, where See also: say, tell, class EndText ! ); ! return 1; } diff -c -r --new-file ds1.1/lib/cmds/players/version.c ds2.1/lib/cmds/players/version.c *** ds1.1/lib/cmds/players/version.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/cmds/players/version.c Wed Jul 5 00:01:03 2006 *************** *** 5,29 **** */ #include <lib.h> #include <daemons.h> #include <localtime.h> inherit LIB_DAEMON; int cmd(string str) { ! string tz, tmp; ! int x, scr, nr; ! tz = (string)this_player()->GetTimeZone() || localtime(time())[LT_ZONE]; ! x = (int)TIME_D->GetOffset(tz) * 3600; scr = ((int *)this_player()->GetScreen())[0]; nr = (time() - uptime()) + ((int)EVENTS_D->GetRebootInterval() * 3600); tmp = center(mud_name(), scr) + "\n"; tmp += sprintf("%:-"+(scr/2)+"s%"+(scr/2)+"s\n", "Driver: " + version(), ! "Library: " + mudlib() + " " + mudlib_version()); tmp += sprintf("%:-" + (scr/2) + "s%" + (scr/2) + "s\n", ! "Up since: " + ctime((time() - uptime()) +x), ! "Next reboot: " + ctime(nr + x)); tmp += center("Current time: " + ctime(time() + x) + " " + tz, scr); message("system", tmp, this_player()); return 1; --- 5,34 ---- */ #include <lib.h> + #include <config.h> #include <daemons.h> #include <localtime.h> inherit LIB_DAEMON; int cmd(string str) { ! string tz, tmp, extra; ! int offset, x, scr, nr; ! if(sizeof(query_os_type())) extra = " for "+query_os_type(); ! tz = query_tz(); ! offset = (int)TIME_D->GetOffset(tz); ! offset += EXTRA_TIME_OFFSET; ! if(query_os_type() != "windows" ) x = offset * 3600; ! else x = 0; scr = ((int *)this_player()->GetScreen())[0]; nr = (time() - uptime()) + ((int)EVENTS_D->GetRebootInterval() * 3600); tmp = center(mud_name(), scr) + "\n"; tmp += sprintf("%:-"+(scr/2)+"s%"+(scr/2)+"s\n", "Driver: " + version(), ! "Library: " + mudlib() + " " + mudlib_version()+extra); tmp += sprintf("%:-" + (scr/2) + "s%" + (scr/2) + "s\n", ! "Up since: " + ctime((time() - uptime()) +x), ! "Next reboot: " + ctime(nr + x)); tmp += center("Current time: " + ctime(time() + x) + " " + tz, scr); message("system", tmp, this_player()); return 1; diff -c -r --new-file ds1.1/lib/cmds/players/where.c ds2.1/lib/cmds/players/where.c *** ds1.1/lib/cmds/players/where.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/cmds/players/where.c Wed Jul 5 00:01:03 2006 *************** *** 19,25 **** foreach(line in explode(str, "\n")) { string site, where; if( sscanf(line, "%s:%s", site, where) == 2 ) ! Sites[site] = where; } } --- 19,25 ---- foreach(line in explode(str, "\n")) { string site, where; if( sscanf(line, "%s:%s", site, where) == 2 ) ! Sites[site] = where; } } *************** *** 44,54 **** int priv; if( arg == "block" ) { ! if( (int)this_player()->GetWhereBlock() ) ! write("Location blocking off."); ! else write("Now blocking location information."); ! this_player()->SetWhereBlock(); ! return 1; } priv = archp(this_player()); arr = ({}); --- 44,54 ---- int priv; if( arg == "block" ) { ! if( (int)this_player()->GetWhereBlock() ) ! write("Location blocking off."); ! else write("Now blocking location information."); ! this_player()->SetWhereBlock(); ! return 1; } priv = archp(this_player()); arr = ({}); *************** *** 59,65 **** if( (int)ob->GetWhereBlock() ) { if( !priv ) str = sprintf("%:-15s Unknown", (string)ob->GetName()); else str = sprintf("%:-15s [%s]", (string)ob->GetName(), ! GetWhere(ob)); } else str = sprintf("%:-15s %s", (string)ob->GetName(), GetWhere(ob)); arr += ({ str }); --- 59,65 ---- if( (int)ob->GetWhereBlock() ) { if( !priv ) str = sprintf("%:-15s Unknown", (string)ob->GetName()); else str = sprintf("%:-15s [%s]", (string)ob->GetName(), ! GetWhere(ob)); } else str = sprintf("%:-15s %s", (string)ob->GetName(), GetWhere(ob)); arr += ({ str }); *************** *** 70,81 **** void help() { write("Syntax: <where>\n\n" ! "Lists all players online and the towns from which those players\n" ! "whose machine site locations are known. If your site is marked\n" ! "<mail superuser> with the town your *machine* is located in and\n" ! "the ip # (four numbers separated by a period).\n" ! "\nOptional: <where [block]>\n\n" ! "Allows you to keep your location anonymous.\n" ! "See also: users, who\n" ); } --- 70,81 ---- void help() { write("Syntax: <where>\n\n" ! "Lists all players online and the towns from which those players\n" ! "whose machine site locations are known. If your site is marked\n" ! "<mail superuser> with the town your *machine* is located in and\n" ! "the ip # (four numbers separated by a period).\n" ! "\nOptional: <where [block]>\n\n" ! "Allows you to keep your location anonymous.\n" ! "See also: users, who\n" ); } diff -c -r --new-file ds1.1/lib/cmds/players/who.c ds2.1/lib/cmds/players/who.c *** ds1.1/lib/cmds/players/who.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/cmds/players/who.c Wed Jul 12 20:17:44 2006 *************** *** 1,67 **** #include <lib.h> #include <config.h> ! inherit LIB_DAEMON; ! ! #define Colours ({\ ! "%^MAGENTA%^",\ ! "%^BOLD%^%^MAGENTA%^",\ ! "%^BOLD%^%^CYAN%^",\ ! "%^CYAN%^",\ ! "%^BLUE%^",\ ! "%^BOLD%^%^BLUE%^",\ ! }) ! ! #define Position ({\ ! "arch",\ ! "creator",\ ! "newbie",\ ! "mortal",\ ! "high mortal",\ ! "avatar",\ ! }) ! ! string AddName(object ob, int x) { ! string str; ! if( query_idle(ob) > 60 ) str = "(idle) "; ! else if( in_input(ob) || in_edit(ob) ) str = "(edit) "; ! else str = " "; ! if( x < 0 || x > 5 ) x = 0; ! return (Colours[x] + str + strip_colours((string)ob->GetShort()) + "%^RESET%^"); ! } ! ! mixed cmd(string args) { ! string *lines; ! mixed group; ! object *avatars, *hms, *norms, *newbies, *adms, *cres, *obs; ! int x, colour, cnt, *screen; ! ! x = sizeof(obs = filter(users(), (: $1->GetName() && ! !((int)$1->GetInvis(this_player())) :))); ! obs = obs - (avatars = filter(obs, (: avatarp :))); ! obs = obs - (hms = filter(obs, (: high_mortalp :))); ! obs = obs - (adms = filter(obs, (: archp :))); ! obs = obs - (cres = filter(obs, (: creatorp :))); ! newbies = obs - ! (norms = filter(obs, (: (int)$1->GetLevel() > MAX_NEWBIE_LEVEL :))); ! screen = (int *)this_player()->GetScreen()[0]; ! colour = sizeof(Colours) - 1; ! cnt = -1; ! lines = ({}); ! foreach(group in ({ adms, cres, newbies, norms, hms, avatars }) ) { ! int i; ! string *tmp; ! cnt++; ! if( !i = sizeof(group) ) continue; ! tmp = ({ capitalize(consolidate(i, Position[cnt])) + ":" }); ! while(i--) tmp += ({ AddName(group[i], colour) }); ! colour--; ! lines = tmp + ({ "" }) + lines; } ! lines = ({ "%^BOLD%^%^BLUE%^" + center(mud_name(), screen), ! center("There are " + x + " members of our reality!", screen), ! "%^RESET%^" }) + lines; ! this_player()->eventPage(lines, "info"); return 1; } ! --- 1,59 ---- + /* Hiccups@Frontiers, 12/16/96 */ + /* Fixes by Haderach, 05 SEP 2005 */ + #include <lib.h> + #include <privs.h> #include <config.h> ! inherit LIB_DAEMON; ! ! #define SEP repeat_string("*=",39)+"*\n"; ! ! int cmd(string args) { ! int p; ! string x, tmp="", ret=""; ! object *obs; ! ! p = 0; ! obs=users(); ! ! for (int i=0; i<sizeof(users()); i++) { ! if(!obs[i] || !environment(obs[i])) continue; ! if(!obs[i]->GetInvis()) { ! if(archp(obs[i])) tmp+="[%^BLUE%^ARCH%^RESET%^]"; ! else if(creatorp(obs[i]) ) tmp+="[%^CYAN%^WIZ%^RESET%^]"; ! else if(avatarp(obs[i]) ) tmp+="[%^GREEN%^AVATAR%^RESET%^]"; ! else if(high_mortalp(obs[i]) ) tmp+="[%^GREEN%^HIGH MORTAL%^RESET%^]"; ! else tmp+=sprintf("[%d]", obs[i]->GetLevel() ); ! if(elderp(obs[i])) tmp+="[%^YELLOW%^ELDER%^RESET%^]"; ! if(ambassadorp(obs[i])) tmp+="[%^YELLOW%^AMBASSADOR%^RESET%^]"; ! tmp += ": "; ! if(sizeof(obs[i]->GetShort()) < 50) { ! tmp+=sprintf(" %s", obs[i]->GetShort()); ! } ! else { ! tmp+=" "+capitalize(obs[i]->GetKeyName())+ " the Long-Titled."; ! } ! if(obs[i]->GetSleeping() > 0) tmp+=" (%^YELLOW%^sleeping%^RESET%^) "; ! else if (obs[i]->GetProperty("afk")) tmp+=" (%^YELLOW%^afk%^RESET%^)"; ! else if (query_idle(obs[i])>240 && obs[i]->GetInCombat()!=1) tmp+=" (%^YELLOW%^idle%^RESET%^)"; ! else if (in_edit(obs[i])) tmp+=" (%^RED%^edit%^RESET%^)"; ! else if(obs[i]->GetInCombat()) tmp+=" (%^RED%^combat%^RESET%^)"; ! tmp+="\n"; ! p++; ! } } ! ret+=center(mud_name()); ! ret+=SEP; ! ret+=tmp; ! ret+=SEP; ! x="There "; ! (p==1) ? x+="is " : x+="are "; ! x+=cardinal(p); ! (p==1) ? x+=" member " : x+=" members "; ! x+="of our reality.\n"; ! ret+=center(x); ! this_player()->eventPrint(""+ret+""); return 1; } ! diff -c -r --new-file ds1.1/lib/cmds/players/wimpy.c ds2.1/lib/cmds/players/wimpy.c *** ds1.1/lib/cmds/players/wimpy.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/cmds/players/wimpy.c Wed Jul 5 00:01:03 2006 *************** *** 18,26 **** percentage = (int)this_player()->GetWimpy(); cmd = (string)this_player()->GetWimpyCommand(); if( !percentage ) ! this_player()->eventPrint("You have wimpy turned off.", MSG_SYSTEM); else this_player()->eventPrint("Percentage: " + percentage + "%\n" ! "Command: " + cmd, MSG_SYSTEM); return 1; } if( args == "0" ) { --- 18,26 ---- percentage = (int)this_player()->GetWimpy(); cmd = (string)this_player()->GetWimpyCommand(); if( !percentage ) ! this_player()->eventPrint("You have wimpy turned off.", MSG_SYSTEM); else this_player()->eventPrint("Percentage: " + percentage + "%\n" ! "Command: " + cmd, MSG_SYSTEM); return 1; } if( args == "0" ) { *************** *** 44,62 **** if( !percentage ) { this_player()->SetWimpy(0); this_player()->eventPrint("Wimpy is now off! You are so brave!", ! MSG_SYSTEM); return 1; } if( percentage > 30 ) { this_player()->eventPrint("You may not set wimpy greater than " ! "30%.", MSG_SYSTEM); return 1; } else if( percentage < 1 ) return "That is not a valid percentage!"; this_player()->SetWimpy(percentage); if( percentage > 20 ) { this_player()->eventPrint("What a weenie! Get some backbone!", ! MSG_SYSTEM); return 1; } else if( percentage > 10 ) { --- 44,62 ---- if( !percentage ) { this_player()->SetWimpy(0); this_player()->eventPrint("Wimpy is now off! You are so brave!", ! MSG_SYSTEM); return 1; } if( percentage > 30 ) { this_player()->eventPrint("You may not set wimpy greater than " ! "30%.", MSG_SYSTEM); return 1; } else if( percentage < 1 ) return "That is not a valid percentage!"; this_player()->SetWimpy(percentage); if( percentage > 20 ) { this_player()->eventPrint("What a weenie! Get some backbone!", ! MSG_SYSTEM); return 1; } else if( percentage > 10 ) { *************** *** 65,108 **** } else { this_player()->eventPrint("You are brave, but not foolish!", ! MSG_SYSTEM); return 1; } } this_player()->SetWimpyCommand(cmd); this_player()->eventPrint("You will execute the command: \"" + cmd + ! "\" next time you wimpy.", MSG_SYSTEM); return 1; } string GetHelp(string str) { return ("Syntax: <wimpy>\n" ! " <wimpy on>\n" ! " <wimpy off>\n" ! " <wimpy PERCENTAGE>\n" ! " <wimpy COMMAND>\n\n" ! "Wimpy is a system that allows you to automatically execute " ! "a command when your health points get below a certain percentage " ! "of your maximum health points. The wimpy command allows you " ! "to set which command will be used at which percentage. " ! "The \"on\" and \"off\" arguments are simply quick ways to " ! "set the percentage to 23% and 0% respectively. You cannot " ! "Set yourself to wimpy at anything greater than 30%.\n" ! "If you set go and enter commands, for example:\n" ! "\tgo west\n" ! "the wimpy system will first try to use that command, and if it " ! "fails, it will search for an exit in the room to take. If " ! "you set another command as your wimpy command, however, other " ! "than a go or enter, it will not make any attempt to execute " ! "some other command.\n" ! "For example, if you issued the command:\n" ! "\twimpy gate to Mystery Person\n" ! "so that \"gate to Mystery Person\" was your wimpy command, " ! "the wimpy system would try to execute that command when you " ! "wimpy and will not try any other command, even if the gate " ! "fails (too low on mp, Mystery Person is not online, etc.).\n" ! "Without any arguments, the wimpy command displays your current " ! "settings.\n\n" ! "See also: attack, status"); } --- 65,108 ---- } else { this_player()->eventPrint("You are brave, but not foolish!", ! MSG_SYSTEM); return 1; } } this_player()->SetWimpyCommand(cmd); this_player()->eventPrint("You will execute the command: \"" + cmd + ! "\" next time you wimpy.", MSG_SYSTEM); return 1; } string GetHelp(string str) { return ("Syntax: <wimpy>\n" ! " <wimpy on>\n" ! " <wimpy off>\n" ! " <wimpy PERCENTAGE>\n" ! " <wimpy COMMAND>\n\n" ! "Wimpy is a system that allows you to automatically execute " ! "a command when your health points get below a certain percentage " ! "of your maximum health points. The wimpy command allows you " ! "to set which command will be used at which percentage. " ! "The \"on\" and \"off\" arguments are simply quick ways to " ! "set the percentage to 23% and 0% respectively. You cannot " ! "Set yourself to wimpy at anything greater than 30%.\n" ! "If you set go and enter commands, for example:\n" ! "\tgo west\n" ! "the wimpy system will first try to use that command, and if it " ! "fails, it will search for an exit in the room to take. If " ! "you set another command as your wimpy command, however, other " ! "than a go or enter, it will not make any attempt to execute " ! "some other command.\n" ! "For example, if you issued the command:\n" ! "\twimpy gate to Mystery Person\n" ! "so that \"gate to Mystery Person\" was your wimpy command, " ! "the wimpy system would try to execute that command when you " ! "wimpy and will not try any other command, even if the gate " ! "fails (too low on mp, Mystery Person is not online, etc.).\n" ! "Without any arguments, the wimpy command displays your current " ! "settings.\n\n" ! "See also: attack, status"); } diff -c -r --new-file ds1.1/lib/cmds/players/xyzzy.c ds2.1/lib/cmds/players/xyzzy.c *** ds1.1/lib/cmds/players/xyzzy.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/cmds/players/xyzzy.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,11 ---- + #include <lib.h> + + inherit LIB_DAEMON; + + mixed cmd(string str) { + if(!creatorp(this_player())) write("Nothing happens."); + else tell_room(environment(this_player()),"A hollow voice says: \"%^CYAN%^Fool!%^RESET%^\""); + return 1; + } + + diff -c -r --new-file ds1.1/lib/daemon/banish.c ds2.1/lib/daemon/banish.c *** ds1.1/lib/daemon/banish.c Sun Feb 1 21:30:00 1998 --- ds2.1/lib/daemon/banish.c Wed Jul 5 00:00:58 2006 *************** *** 3,21 **** * maintains information on legitimate character creation * created by Descartes of Borg 940115 */ ! #include <lib.h> #include <config.h> #include <objects.h> #include <daemons.h> #include <save.h> ! inherit LIB_DAEMON; ! string *__Names, *__Sites, *__WatchNames, *__WatchSites; string *__Allowed, *__Guests, *__IllegalSubStrings; mapping __TmpBanish; ! static private int valid_access(object ob); void register_site(string str); void temporary_register(string str, int time); --- 3,22 ---- * maintains information on legitimate character creation * created by Descartes of Borg 940115 */ ! #include <lib.h> + #include <privs.h> #include <config.h> #include <objects.h> #include <daemons.h> #include <save.h> ! inherit LIB_DAEMON; ! string *__Names, *__Sites, *__WatchNames, *__WatchSites; string *__Allowed, *__Guests, *__IllegalSubStrings; mapping __TmpBanish; ! static private int valid_access(object ob); void register_site(string str); void temporary_register(string str, int time); *************** *** 48,54 **** int valid_name(string str); int eventConnect(string nom, string ip); static private int match_ip(string ip, string *sites); ! void create() { daemon::create(); SetNoClean(1); --- 49,55 ---- int valid_name(string str); int eventConnect(string nom, string ip); static private int match_ip(string ip, string *sites); ! void create() { daemon::create(); SetNoClean(1); *************** *** 61,78 **** __IllegalSubStrings = ({}); __TmpBanish=([]); if(file_exists(SAVE_BANISH+__SAVE_EXTENSION__)) ! restore_banish(); if(!__TmpBanish) __TmpBanish = ([]); clean_temp_sites(); } ! static private int valid_access(object ob) { ! return (int)master()->valid_apply( ({ "LAW", "SUPERUSER" }) ); } ! int valid_cap_name(string cap, string nom) { int i; ! if(convert_name(cap) != nom) return 0; if((i = strlen(cap)) > MAX_USER_CAP_NAME_LENGTH) return 0; if(strsrch(cap, "'-") != -1) return 0; --- 62,79 ---- __IllegalSubStrings = ({}); __TmpBanish=([]); if(file_exists(SAVE_BANISH+__SAVE_EXTENSION__)) ! restore_banish(); if(!__TmpBanish) __TmpBanish = ([]); clean_temp_sites(); } ! static private int valid_access(object ob) { ! return (int)master()->valid_apply( ({ "ASSIST" }) ); } ! int valid_cap_name(string cap, string nom) { int i; ! if(convert_name(cap) != nom) return 0; if((i = strlen(cap)) > MAX_USER_CAP_NAME_LENGTH) return 0; if(strsrch(cap, "'-") != -1) return 0; *************** *** 85,102 **** if(strsrch(cap, " -") != -1) return 0; if(strsrch(cap, " ") != -1) return 0; if(lower_case(cap[i-1..i-1]) != nom[strlen(nom)-1..strlen(nom)-1]) ! return 0; return 1; } ! void register_site(string str) { if(!valid_access(previous_object())) return; if(member_array(str, keys(__TmpBanish))!=-1) ! map_delete(__TmpBanish,str); __Sites = distinct_array(__Sites + ({ str }) ); save_banish(); } ! void temporary_register(string str, int foo) { if(!valid_access(previous_object())) return; foo+=time(); --- 86,103 ---- if(strsrch(cap, " -") != -1) return 0; if(strsrch(cap, " ") != -1) return 0; if(lower_case(cap[i-1..i-1]) != nom[strlen(nom)-1..strlen(nom)-1]) ! return 0; return 1; } ! void register_site(string str) { if(!valid_access(previous_object())) return; if(member_array(str, keys(__TmpBanish))!=-1) ! map_delete(__TmpBanish,str); __Sites = distinct_array(__Sites + ({ str }) ); save_banish(); } ! void temporary_register(string str, int foo) { if(!valid_access(previous_object())) return; foo+=time(); *************** *** 104,280 **** __Sites = distinct_array(__Sites + ({str})); save_banish(); } ! string query_temp_site_info() { string info, *site; int i; if(!valid_access(previous_object())) return ""; for(i=0,info="";i<sizeof(site=keys(__TmpBanish));i++) ! info+= site[i]+" will expire at "+ctime(__TmpBanish[site[i]])+".\n"; if(!info) info = "No sites are on temporary registration."; return info; } ! void manual_temp_unregister(string str) { ! string *sites; ! if(!valid_access(previous_object())) return; if(member_array(str, keys(__TmpBanish))==-1) return; map_delete(__TmpBanish,str); __Sites -= ({str}); save_banish(); } ! void clean_temp_sites() { int *times,i; string *sites; ! ! times=values(__TmpBanish); sites=keys(__TmpBanish); ! for(i=0;i<sizeof(times);i++) { ! if(times[i]<time()) { ! map_delete(__TmpBanish,sites[i]); ! __Sites -= ({sites[i]}); ! } } save_banish(); call_out("clean_temp_sites", 900); } ! void unregister_site(string str) { if(!valid_access(previous_object())) return; __Sites -= ({ str }); save_banish(); } ! string *query_registered() { if(!valid_access(previous_object())) return ({}); return __Sites; } ! void banish_name(string str) { ! unguarded( (: log_file, "banish", ! (string)this_player()->GetName() + " banished " + str + "." :) ); __Names = distinct_array(__Names + ({ lower_case(str) })); save_banish(); } ! void unbanish_name(string str) { if(!valid_access(previous_object())) return; __Names -= ({ lower_case(str) }); save_banish(); } ! string *query_banished() { if(!valid_access(previous_object())) return ({}); return __Names; } ! void watch_site(string str) { if(!valid_access(previous_object())) return; __WatchSites = distinct_array(__WatchSites + ({ str })); save_banish(); } ! void unwatch_site(string str) { if(!valid_access(previous_object())) return; __WatchSites -= ({ str }); save_banish(); } ! string *query_watched_sites() { if(!valid_access(previous_object())) return ({}); return __WatchSites; } ! void watch_name(string str) { if(!valid_access(previous_object())) return; __WatchNames = distinct_array(__WatchNames + ({ lower_case(str) })); save_banish(); } ! void unwatch_name(string str) { if(!valid_access(previous_object())) return; __WatchNames -= ({ lower_case(str) }); save_banish(); } ! string *query_watched_names() { if(!valid_access(previous_object())) return ({}); return __WatchNames; } ! void allow_name(string str) { if(!valid_access(previous_object())) return; __Allowed = distinct_array(__Allowed + ({ lower_case(str) })); save_banish(); } ! void unallow_name(string str) { if(!valid_access(previous_object())) return; __Allowed -= ({ lower_case(str) }); save_banish(); } ! string *query_allowed() { if(!valid_access(previous_object())) return ({}); return __Allowed; } ! void set_illegal_substring(string str) { if(!valid_access(previous_object())) return; __IllegalSubStrings = distinct_array(__IllegalSubStrings + ({ lower_case(str) })); save_banish(); } ! void remove_illegal_substring(string str) { if(!valid_access(previous_object())) return; __IllegalSubStrings -= ({ lower_case(str) }); save_banish(); } ! string *query_illegal_substrings() { if(!valid_access(previous_object())) return ({}); else return __IllegalSubStrings; } ! void add_guest(string str) { if(!valid_access(previous_object())) return; __Guests = distinct_array(__Guests + ({ lower_case(str) })); save_banish(); } ! void remove_guest(string str) { if(!valid_access(previous_object())) return; __Guests -= ({ lower_case(str) }); save_banish(); } ! string *query_guests() { if(!valid_access(previous_object())) return ({}); else return __Guests; } ! static private void save_banish() { save_object(SAVE_BANISH); } ! static private void restore_banish() { restore_object(SAVE_BANISH); } ! int GetGuest(string str) { if(base_name(previous_object()) != LIB_CONNECT ) return 0; else return (member_array(lower_case(str), __Guests) != -1); } ! int valid_name(string str) { int i, x; ! if(base_name(previous_object()) != LIB_CONNECT ) return 0; if(member_array(str, __Names) != -1) return 0; i = sizeof(__IllegalSubStrings); --- 105,281 ---- __Sites = distinct_array(__Sites + ({str})); save_banish(); } ! string query_temp_site_info() { string info, *site; int i; if(!valid_access(previous_object())) return ""; for(i=0,info="";i<sizeof(site=keys(__TmpBanish));i++) ! info+= site[i]+" will expire at "+ctime(__TmpBanish[site[i]])+".\n"; if(!info) info = "No sites are on temporary registration."; return info; } ! void manual_temp_unregister(string str) { ! if(!valid_access(previous_object())) return; if(member_array(str, keys(__TmpBanish))==-1) return; map_delete(__TmpBanish,str); __Sites -= ({str}); save_banish(); } ! void clean_temp_sites() { int *times,i; string *sites; ! ! times=values(__TmpBanish); sites=keys(__TmpBanish); ! for(i=0;i<sizeof(times);i++) { ! if(times[i]<time()) { ! map_delete(__TmpBanish,sites[i]); ! __Sites -= ({sites[i]}); ! } } save_banish(); call_out("clean_temp_sites", 900); } ! void unregister_site(string str) { if(!valid_access(previous_object())) return; __Sites -= ({ str }); save_banish(); } ! string *query_registered() { if(!valid_access(previous_object())) return ({}); return __Sites; } ! void banish_name(string str) { ! if(!valid_access(previous_object())) return; ! unguarded( (: log_file, "banish", ! (string)this_player()->GetName() + " banished " + str + "." :) ); __Names = distinct_array(__Names + ({ lower_case(str) })); save_banish(); } ! void unbanish_name(string str) { if(!valid_access(previous_object())) return; __Names -= ({ lower_case(str) }); save_banish(); } ! string *query_banished() { if(!valid_access(previous_object())) return ({}); return __Names; } ! void watch_site(string str) { if(!valid_access(previous_object())) return; __WatchSites = distinct_array(__WatchSites + ({ str })); save_banish(); } ! void unwatch_site(string str) { if(!valid_access(previous_object())) return; __WatchSites -= ({ str }); save_banish(); } ! string *query_watched_sites() { if(!valid_access(previous_object())) return ({}); return __WatchSites; } ! void watch_name(string str) { if(!valid_access(previous_object())) return; __WatchNames = distinct_array(__WatchNames + ({ lower_case(str) })); save_banish(); } ! void unwatch_name(string str) { if(!valid_access(previous_object())) return; __WatchNames -= ({ lower_case(str) }); save_banish(); } ! string *query_watched_names() { if(!valid_access(previous_object())) return ({}); return __WatchNames; } ! void allow_name(string str) { if(!valid_access(previous_object())) return; __Allowed = distinct_array(__Allowed + ({ lower_case(str) })); save_banish(); } ! void unallow_name(string str) { if(!valid_access(previous_object())) return; __Allowed -= ({ lower_case(str) }); save_banish(); } ! string *query_allowed() { if(!valid_access(previous_object())) return ({}); return __Allowed; } ! void set_illegal_substring(string str) { if(!valid_access(previous_object())) return; __IllegalSubStrings = distinct_array(__IllegalSubStrings + ({ lower_case(str) })); save_banish(); } ! void remove_illegal_substring(string str) { if(!valid_access(previous_object())) return; __IllegalSubStrings -= ({ lower_case(str) }); save_banish(); } ! string *query_illegal_substrings() { if(!valid_access(previous_object())) return ({}); else return __IllegalSubStrings; } ! void add_guest(string str) { if(!valid_access(previous_object())) return; __Guests = distinct_array(__Guests + ({ lower_case(str) })); save_banish(); } ! void remove_guest(string str) { if(!valid_access(previous_object())) return; __Guests -= ({ lower_case(str) }); save_banish(); } ! string *query_guests() { if(!valid_access(previous_object())) return ({}); else return __Guests; } ! static private void save_banish() { save_object(SAVE_BANISH); } ! static private void restore_banish() { restore_object(SAVE_BANISH); } ! int GetGuest(string str) { if(base_name(previous_object()) != LIB_CONNECT ) return 0; else return (member_array(lower_case(str), __Guests) != -1); } ! int valid_name(string str) { int i, x; ! if(base_name(previous_object()) != LIB_CONNECT ) return 0; if(member_array(str, __Names) != -1) return 0; i = sizeof(__IllegalSubStrings); *************** *** 282,333 **** if((x = strlen(str)) > MAX_USER_NAME_LENGTH) return 0; if(x < MIN_USER_NAME_LENGTH) return 0; for(i=0; i<x; i++) ! if(str[i] < 'a' || str[i] > 'z') return 0; return 1; } ! int eventConnect(string nom, string ip) { if(base_name(previous_object()) != LIB_CONNECT ) return 0; if(member_array(nom, __WatchNames) != -1) { ! log_file("watch/names", sprintf("%s from %s at %s\n", nom, ip, ! ctime(time()))); } if(match_ip(ip, __WatchSites)) { ! log_file("watch/"+ip, sprintf("%s at %s\n", nom, ctime(time()))); } if(member_array(nom, __Allowed) != -1) { ! log_file("watch/allowed", sprintf("%s from %s at %s\n", nom, ip, ! ctime(time()))); ! __Allowed -= ({ nom }); ! save_banish(); ! return 1; } if(match_ip(ip, __Sites)) { ! if(user_exists(nom)) { ! log_file("watch/"+ip, sprintf("%s allowed in from %s at %s\n", ! nom, ip, ! ctime(time()))); ! return 1; ! } ! else { ! log_file("watch/"+ip, sprintf("%s failed from %s at %s\n" ! , nom, ! ip, ! ctime(time()))); ! return 0; ! } } return 1; } ! static private int match_ip(string ip, string *sites) { foreach(string site in sites) { ! int i; if( site == ip ) return 1; i = strsrch(site, "*"); if( i > 0 ) { ! if( ip[0..(i-1)] == site[0..(i-1)] ) return 1; } } return 0; --- 283,334 ---- if((x = strlen(str)) > MAX_USER_NAME_LENGTH) return 0; if(x < MIN_USER_NAME_LENGTH) return 0; for(i=0; i<x; i++) ! if(str[i] < 'a' || str[i] > 'z') return 0; return 1; } ! int eventConnect(string nom, string ip) { if(base_name(previous_object()) != LIB_CONNECT ) return 0; if(member_array(nom, __WatchNames) != -1) { ! log_file("watch/names", sprintf("%s from %s at %s\n", nom, ip, ! ctime(time()))); } if(match_ip(ip, __WatchSites)) { ! log_file("watch/"+ip, sprintf("%s at %s\n", nom, ctime(time()))); } if(member_array(nom, __Allowed) != -1) { ! log_file("watch/allowed", sprintf("%s from %s at %s\n", nom, ip, ! ctime(time()))); ! __Allowed -= ({ nom }); ! save_banish(); ! return 1; } if(match_ip(ip, __Sites)) { ! if(user_exists(nom)) { ! log_file("watch/"+ip, sprintf("%s allowed in from %s at %s\n", ! nom, ip, ! ctime(time()))); ! return 1; ! } ! else { ! log_file("watch/"+ip, sprintf("%s failed from %s at %s\n" ! , nom, ! ip, ! ctime(time()))); ! return 0; ! } } return 1; } ! static private int match_ip(string ip, string *sites) { foreach(string site in sites) { ! int i; if( site == ip ) return 1; i = strsrch(site, "*"); if( i > 0 ) { ! if( ip[0..(i-1)] == site[0..(i-1)] ) return 1; } } return 0; diff -c -r --new-file ds1.1/lib/daemon/bugs.c ds2.1/lib/daemon/bugs.c *** ds1.1/lib/daemon/bugs.c Sun Feb 1 21:30:00 1998 --- ds2.1/lib/daemon/bugs.c Wed Jul 5 00:00:58 2006 *************** *** 22,28 **** daemon::create(); if( file_size(SAVE_BUGS __SAVE_EXTENSION__) > 0 ) ! unguarded( (: restore_object, SAVE_BUGS :)); if( NextID < 1 || !Bugs ) { NextID = 1; Bugs = ([]); --- 22,28 ---- daemon::create(); if( file_size(SAVE_BUGS __SAVE_EXTENSION__) > 0 ) ! unguarded( (: restore_object, SAVE_BUGS :)); if( NextID < 1 || !Bugs ) { NextID = 1; Bugs = ([]); *************** *** 31,40 **** foreach(bug_id, bug in Bugs) { if( !bug["date assigned"] ) continue; if( t - bug["date assigned"] > UNCOMPLETED_LIFE ) ! map_delete(Bugs, bug_id); else if( bug["date assigned"] && bug["date fixed"] ) { if( t - bug["date fixed"] > COMPLETED_LIFE ) ! map_delete(Bugs, bug_id); } } unguarded( (: save_object, SAVE_BUGS :)); --- 31,40 ---- foreach(bug_id, bug in Bugs) { if( !bug["date assigned"] ) continue; if( t - bug["date assigned"] > UNCOMPLETED_LIFE ) ! map_delete(Bugs, bug_id); else if( bug["date assigned"] && bug["date fixed"] ) { if( t - bug["date fixed"] > COMPLETED_LIFE ) ! map_delete(Bugs, bug_id); } } unguarded( (: save_object, SAVE_BUGS :)); *************** *** 79,85 **** x = NextID++; Bugs[x] = ([ "who" : who, "type" : type, "bug" : bug, "data" : data, ! "assigned" : 0, "date fixed" : 0, "resolution" : 0 ]); if( unguarded( (: save_object, SAVE_BUGS :) ) ) return x; else { map_delete(Bugs, x); --- 79,85 ---- x = NextID++; Bugs[x] = ([ "who" : who, "type" : type, "bug" : bug, "data" : data, ! "assigned" : 0, "date fixed" : 0, "resolution" : 0 ]); if( unguarded( (: save_object, SAVE_BUGS :) ) ) return x; else { map_delete(Bugs, x); *************** *** 92,99 **** int id, x = 0; foreach( id, rep in Bugs) ! if( rep["assigned"] && !rep["date fixed"] && ! (convert_name(rep["assigned"]) == who) ) x++; return x; } --- 92,99 ---- int id, x = 0; foreach( id, rep in Bugs) ! if( rep["assigned"] && !rep["date fixed"] && ! (convert_name(rep["assigned"]) == who) ) x++; return x; } diff -c -r --new-file ds1.1/lib/daemon/chat.c ds2.1/lib/daemon/chat.c *** ds1.1/lib/daemon/chat.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/chat.c Wed Dec 31 19:00:00 1969 *************** *** 1,378 **** - /* /daemon/chat.c - * from the Dead Souls 3.2 Mudlib - * daemon to handle all mud chat channels - * created by Descartes of Borg 931220 - */ - - #include <lib.h> - #include <pov.h> - #include <daemons.h> - #include <origin.h> - #include <message_class.h> - #include "include/chat.h" - - inherit LIB_DAEMON; - - static private mapping Channels; - - static void create() { - object pl; - - daemon::create(); - SetNoClean(1); - Channels = ([]); - foreach(pl in users()) { - string *chans; - string channel; - - if( !(chans = (string *)pl->GetChannels()) ) continue; - foreach(channel in chans) { - if( !Channels[channel] ) Channels[channel] = ({}); - Channels[channel] = distinct_array(Channels[channel] + ({ pl })); - } - } - } - - string *eventRegisterMember(string *chans) { - string *tmp; - object ob; - string channel; - - if( !living(ob = previous_object()) ) return ({}); - tmp = ({}); - foreach(channel in chans) { - /* just check out for secure channels */ - switch(channel) { - case "admin": - if( !archp(ob) ) break; - case "cre": case "intercre": case "gossip": case "intergossip": - if( !creatorp(ob) ) break; - default: - if( !Channels[channel]) Channels[channel] = ({}); - Channels[channel] = distinct_array(Channels[channel] + ({ ob })); - tmp += ({ channel }); - } - } - return tmp; - } - - string *eventRemoveMember(string *chans) { - object ob; - string channel; - - if( !living(ob = previous_object()) ) return({}); - foreach(channel in chans) { - if( !Channels[channel] ) continue; - else Channels[channel] -= ({ ob }); - if( !sizeof(Channels[channel]) ) map_delete(Channels, channel); - } - return chans; - } - - int cmdChannel(string verb, string str) { - string msg, name, rc, target, targetkey, target_msg; - object ob = 0; - int emote; - - if( verb == "list" ) { - string *who; - string ch, mud; - - if( !str ) return 0; - if( sscanf(str, "%s@%s", ch, mud) == 2 ) { - if( !Channels[ch] ) return 0; - if( member_array(this_player(), Channels[ch]) == -1 ) return 0; - if( ch == (ch = GetRemoteChannel(ch)) ) return 0; - if( !(mud = (string)INTERMUD_D->GetMudName(mud)) ) { - this_player()->eventPrint(mud_name() + " is not aware of " - "such a place.", MSG_ERROR); - return 1; - } - SERVICES_D->eventSendChannelWhoRequest(ch, mud); - this_player()->eventPrint("Remote listing request sent.", - MSG_SYSTEM); - return 1; - } - else ch = str; - if( !Channels[ch] ) return 0; - if( member_array(this_player(), Channels[str]) == -1 ) return 0; - who = GetChannelList(str); - msg = "Online: " + implode(who, " "); - this_player()->eventPrint(msg, MSG_SYSTEM); - return 1; - } - if( !Channels[verb] ) { - if( sscanf(verb, "%semote", verb) ) { - string emote_cmd, remains; - mixed array msg_data; - int i; - - if( !Channels[verb] ) { - return 0; - } - rc = GetRemoteChannel(verb); - sscanf(str, "%s %s", emote_cmd, remains); - if( !emote_cmd ) { - emote_cmd = str; - remains = 0; - } - if( !remains ) { - msg_data = SOUL_D->GetChannelEmote(emote_cmd, ""); - if( !msg_data ) { - str = "$N " + str; - } - } - else { - if( ob = find_living(target = convert_name(remains)) ) { - msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LIV"); - if( !msg_data ) { - str = "$N " + str; - target = 0; - } - } - else if( strsrch(target, "@") == -1 || rc == verb ) { - string array words = explode(remains, " "); - - target = ""; - for(i=0; i<sizeof(words); i++) { - target += lower_case(words[i]); - if( ob = find_living(target) ) { - if( i < sizeof(words)-1 ) { - remains = implode(words[(i+1)..], " "); - } - else { - remains = 0; - } - msg_data = SOUL_D->GetChannelEmote(emote_cmd, - "LIV STR", - remains); - break; - } - } - if( !ob ) { - msg_data = SOUL_D->GetChannelEmote(emote_cmd, "STR", - remains); - target = 0; - } - if( !msg_data ) { - str = "$N " + str; - target = 0; - } - } - else if( rc != verb ) { - string array words; - - i = strsrch(remains, "@", -1); - if( i >= strlen(remains)-1 ) { - msg_data = SOUL_D->GetChannelEmote(emote_cmd, "STR", - remains); - target = 0; - } - else { - string mud; - int test = 3; - - words = explode(remains[(i+1)..], " "); - target = remains[0..i]; - remains = ""; - while(sizeof(words)) { - mud = implode(words, " "); - mud = INTERMUD_D->GetMudName(lower_case(mud)); - if( mud ) { - target += mud; - break; - } - if( remains == "" ) { - remains = words[<1]; - } - else { - remains = words[<1] + " " + remains; - } - words = words[0..<2]; - } - if( !mud ) { - msg_data = SOUL_D->GetChannelEmote(emote_cmd, - "STR", remains); - target = 0; - } - else { - if( trim(remains) == "" ) { - msg_data = SOUL_D->GetChannelEmote(emote_cmd, - "LIV"); - } - else { - msg_data = SOUL_D->GetChannelEmote(emote_cmd, - "LIV STR", - remains); - } - if( !msg_data ) { - str = "$N " + str; - target = 0; - } - } - } - } - } - if( msg_data ) { - string sgen = this_player()->GetGender(); - string tgen = 0; - - if( ob ) { - target = ob->GetName(); - tgen = ob->GetGender(); - } - else if( target ) { - string user, mud; - - sscanf(target, "%s@%s", user, mud); - targetkey = target; - tgen = SERVICES_D->GetRemoteGender(user, mud); - target = SERVICES_D->GetRemoteDisplayName(user, mud); - if( !target ) { - target = capitalize(targetkey); - } - } - str = create_message(POV_OBSERVER, msg_data[0][0], - msg_data[0][1], "$N", sgen, "$O", tgen, - msg_data[1]); - if( target ) { - target_msg = create_message(POV_TARGET, msg_data[0][0], - msg_data[0][1], "$N", sgen, - "$O", tgen, msg_data[1]); - } - } - emote = 1; - } - else { - return 0; - } - } - else { - rc = GetRemoteChannel(verb); - } - if( member_array(this_player(), Channels[verb]) == -1 ) return 0; - if( !str || str == "" ) { - this_player()->SetBlocked(verb); - return 1; - } - if( (int)this_player()->GetBlocked(verb) ) { - if( (int)this_player()->GetBlocked("all") ) { - this_player()->eventPrint("You cannot chat while totally blocked.", - MSG_ERROR); - return 1; - } - this_player()->SetBlocked(verb); - } - if( verb == "admin" || verb=="cre" ) { - if( !(name = (string)this_player()->GetCapName()) ) - name = capitalize((string)this_player()->GetKeyName()); - } - else name = (string)this_player()->GetName(); - if( target_msg ) { - target_msg = replace_string(target_msg, "$O's", "your"); - } - eventSendChannel(name, verb, str, emote, target, target_msg); - if( rc != verb ) { - if( ob ) { - SERVICES_D->eventSendChannel(name, rc, str, emote, target, - target_msg); - } - else { - SERVICES_D->eventSendChannel(name, rc, str, emote, targetkey, - target_msg); - } - } - return 1; - } - - varargs void eventSendChannel(string who, string ch, string msg, int emote, - string target, string targmsg) { - if( file_name(previous_object()) == SERVICES_D) { - ch = GetLocalChannel(ch); - if( emote ) msg = replace_string(msg, "$N", who); - } - else if( origin() != ORIGIN_LOCAL && previous_object() != master() && - file_name(previous_object()) != PARTY_D ) return; - if( !Channels[ch] ) return; - if( emote ) { - object *obs; - object ob; - string this_msg, tmp; - int len; - - if( target && (ob = find_player(convert_name(target))) ) { - target = (string)ob->GetName(); - } - this_msg = "%^MAGENTA%^<" + ch + ">%^RESET%^ "; - msg = replace_string(msg, "$N", who); - if( target ) { - msg = replace_string(msg, "$O", target); - targmsg = replace_string(targmsg, "$N", who); - targmsg = capitalize(replace_string(targmsg, "$O", "you")); - } - obs = filter(Channels[ch], (: $1 && !((int)$1->GetBlocked($(ch))) :)); - tmp = this_msg + msg; - foreach(object listener in obs) { - if( listener == ob ) continue; - listener->eventPrint(tmp, MSG_CONV); - } - if( member_array(ob, obs) != -1 ) { - if( ob && !((int)ob->GetBlocked(ch)) ) { - tmp = this_msg + targmsg; - ob->eventPrint(tmp, MSG_CONV); - } - } - } - else { - object *obs; - - msg = who + " %^MAGENTA%^<" + ch + ">%^RESET%^ " + msg; - obs = filter(Channels[ch], (: $1 && !((int)$1->GetBlocked($(ch))) :)); - obs->eventPrint(msg, MSG_CONV); - } - } - - string *GetChannelList(string ch) { - string *ret; - object who; - string list; - int i; - - if( file_name(previous_object()) == SERVICES_D ) ch = GetLocalChannel(ch); - else if( origin() != ORIGIN_LOCAL ) return ({}); - if( !Channels[ch] ) return ({}); - ret = ({}); - foreach(who in Channels[ch]) { - if( !who || (int)who->GetInvis() || (int)who->GetBlocked(ch) ) - continue; - ret += ({ (string)who->GetName() }); - } - return ret; - } - - string GetLocalChannel(string ch) { - switch(ch) { - case "imud_code": - return "intercre"; - - case "imud_gossip": - return "intergossip"; - } - return ch; - } - - string GetRemoteChannel(string ch) { - switch(ch) { - case "intercre": - return "imud_code"; - - case "intergossip": - return "imud_gossip"; - - case "foundation": - return "ie_flibcode"; - } - return ch; - } - - string *GetChannels() { return copy(keys(Channels)); } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/classes.c ds2.1/lib/daemon/classes.c *** ds1.1/lib/daemon/classes.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/classes.c Wed Jul 5 00:00:58 2006 *************** *** 44,159 **** class Class cls; string array lines, tmp; string class_name; ! validate(); if( !file_exists(file) ) error("No such file: " + file); lines = explode(read_file(file), "\n"); lines = filter(lines, function(string str) { ! if( strlen(str) == 0 ) { ! return 0; ! } ! if( str[0] == '#' ) { ! return 0; ! } ! if( str[0] == ' ' || str[0] == '\t' ) { ! return 0; ! } ! return 1; ! }); ! class_name = lines[0]; ! if( Classes[class_name] ) error("Class already exists"); ! cls = new(class Class); ! Classes[class_name] = cls; ! lines = lines[1..]; ! cls->Multis = ([]); ! while( sizeof(tmp = explode(lines[0], ":")) == 2 ) { ! cls->Multis[tmp[0]] = tmp[1]; ! lines = lines[1..]; } ! cls->Skills = ([]); ! while(sizeof(tmp = explode(lines[0], ":")) == 3) { ! class Skill s = new (class Skill); ! ! s->Average = to_int(tmp[1]); ! s->SkillClass = to_int(tmp[2]); ! cls->Skills[tmp[0]] = s; ! if( sizeof(lines) == 1 ) { ! lines = ({}); ! break; ! } ! else { ! lines = lines[1..]; } } - cls->Complete = 1; - save_object(SAVE_CLASSES); - } ! void RemoveClass(string class_name) { ! validate(); ! map_delete(Classes, class_name); ! save_object(SAVE_CLASSES); ! } ! ! void SetClass(string class_name, mixed array args) { ! class Class cls = Classes[class_name]; ! mixed array primes, ots; ! ! if( !cls || !cls->Complete || sizeof(args) != 3 ) return; ! args[0] = cls->Multis; ! primes = ({}); ! ots = ({}); ! foreach(string key, class Skill skill in cls->Skills) { ! if( skill->SkillClass == 1 ) { ! primes = ({ primes..., ({ key, skill->Average, 1 }) }); ! } ! else { ! ots = ({ ots..., ({ key, skill->Average, skill->SkillClass }) }); ! } } ! args[1] = primes; ! args[2] = ots; ! } ! ! void SetComplete(string class_name) { ! class Class cls; ! ! validate(); ! if( !Classes[class_name] ) error("No such class"); ! else cls = Classes[class_name]; ! cls->Complete = 1; ! save_object(SAVE_CLASSES); ! } ! ! varargs string array GetClasses() { ! return filter(keys(Classes), (: ((class Class)Classes[$1])->Complete :)); ! } ! ! string GetHelp(string class_name) { ! class Class cls = Classes[class_name]; ! string help = "Class: " + class_name + "\n\n"; ! string tmp; ! int x; ! ! if( !cls ) return 0; ! if( !sizeof(cls->Multis) ) { ! help += capitalize(class_name) + " cannot multi-class.\n"; } ! else { ! help += capitalize(pluralize(class_name)) + " can multi-class with " + ! "the following primary classes:\n"; ! foreach(string prime, string other in cls->Multis) { ! help += "\t" + capitalize(class_name) + " + " + prime + " = " + other + "\n"; } ! } ! help += "\n" + capitalize(pluralize(class_name)) + " has the following " + "primary skills:\n"; ! foreach(string skill, class Skill s in cls->Skills) { ! if( s->SkillClass == 1 ) { ! help += "\t" + skill + "\n"; } } ! return help + "\n"; ! } ! --- 44,157 ---- class Class cls; string array lines, tmp; string class_name; ! validate(); if( !file_exists(file) ) error("No such file: " + file); lines = explode(read_file(file), "\n"); lines = filter(lines, function(string str) { ! if( strlen(str) == 0 ) { ! return 0; ! } ! if( str[0] == '#' ) { ! return 0; ! } ! if( str[0] == ' ' || str[0] == '\t' ) { ! return 0; ! } ! return 1; ! }); ! class_name = lines[0]; ! if( Classes[class_name] ) error("Class already exists"); ! cls = new(class Class); ! Classes[class_name] = cls; ! lines = lines[1..]; ! cls->Multis = ([]); ! while( sizeof(tmp = explode(lines[0], ":")) == 2 ) { ! cls->Multis[tmp[0]] = tmp[1]; ! lines = lines[1..]; ! } ! cls->Skills = ([]); ! while(sizeof(tmp = explode(lines[0], ":")) == 3) { ! class Skill s = new (class Skill); ! ! s->Average = to_int(tmp[1]); ! s->SkillClass = to_int(tmp[2]); ! cls->Skills[tmp[0]] = s; ! if( sizeof(lines) == 1 ) { ! lines = ({}); ! break; ! } ! else { ! lines = lines[1..]; ! } ! } ! cls->Complete = 1; ! save_object(SAVE_CLASSES); ! } ! ! void RemoveClass(string class_name) { ! validate(); ! map_delete(Classes, class_name); ! save_object(SAVE_CLASSES); } ! ! void SetClass(string class_name, mixed array args) { ! class Class cls = Classes[class_name]; ! mixed array primes, ots; ! ! if( !cls || !cls->Complete || sizeof(args) != 3 ) return; ! args[0] = cls->Multis; ! primes = ({}); ! ots = ({}); ! foreach(string key, class Skill skill in cls->Skills) { ! if( skill->SkillClass == 1 ) { ! primes = ({ primes..., ({ key, skill->Average, 1 }) }); ! } ! else { ! ots = ({ ots..., ({ key, skill->Average, skill->SkillClass }) }); ! } } + args[1] = primes; + args[2] = ots; } ! void SetComplete(string class_name) { ! class Class cls; ! ! validate(); ! if( !Classes[class_name] ) error("No such class"); ! else cls = Classes[class_name]; ! cls->Complete = 1; ! save_object(SAVE_CLASSES); } ! ! varargs string array GetClasses() { ! return filter(keys(Classes), (: ((class Class)Classes[$1])->Complete :)); } ! ! string GetHelp(string class_name) { ! class Class cls = Classes[class_name]; ! string help = "Class: " + class_name + "\n\n"; ! ! if( !cls ) return 0; ! if( !sizeof(cls->Multis) ) { ! help += capitalize(class_name) + " cannot multi-class.\n"; ! } ! else { ! help += capitalize(pluralize(class_name)) + " can multi-class with " + ! "the following primary classes:\n"; ! foreach(string prime, string other in cls->Multis) { ! help += "\t" + capitalize(class_name) + " + " + prime + " = " + other + "\n"; + } } ! help += "\n" + capitalize(pluralize(class_name)) + " has the following " + "primary skills:\n"; ! foreach(string skill, class Skill s in cls->Skills) { ! if( s->SkillClass == 1 ) { ! help += "\t" + skill + "\n"; ! } } + return help + "\n"; } ! diff -c -r --new-file ds1.1/lib/daemon/combat.c ds2.1/lib/daemon/combat.c *** ds1.1/lib/daemon/combat.c Sun Feb 1 21:30:00 1998 --- ds2.1/lib/daemon/combat.c Wed Dec 31 19:00:00 1969 *************** *** 1,110 **** - /* /daemon/combat.c - * From the Dead Souls V Object Library - * Single point for storing the large arrays where combat messages are - * defined. - * Created by Descartes of Borg 961117 - * Version: %A% - * Last modified: %D% - */ - - #include <lib.h> - - inherit LIB_DAEMON; - - private mixed array BLADES = ({ - // no damage - ({ ({ ({ "take" }), "$target_verb the cut from $limb without a " - "flinch." }) }), - // damage < 5 - ({ ({ ({ "prick" }), "$agent_verb $target_name lightly in the $limb with " - "$using." }), - ({ ({ "prick" }), "$agent_verb $target_name superficially in the $limb " - "with $using." }), - ({ ({ "prick" }), "just barely $agent_verb $target_name in the $limb " - "with $using." }) }), - // damage < 10 - ({ ({ ({ "prick" }), "$agent_verb $target_name decently in the $limb with " - "$using." }), - ({ ({ "prick" }), "$agent_verb $target_name annoyingly in the $limb " - "with $using." }), - ({ ({ "prick" }), "solidly $agent_verb $target_name in the $limb " - "with $using." }) }), - // damage < 15 - ({ ({ ({ "scratch" }), "$agent_verb $target_name mildly in the $limb " - "with $using."}), - ({ ({ "scratch" }), "barely $agent_verb $target_name in the $limb " - "with $using." }), - ({ ({ "scratch" }), "$agent_verb $target_name in the $limb with " - "$using." }) }), - // damage < 20 - ({ ({ ({ "scratch" }), "$agent_verb $target_name nastily in the $limb " - "with $using." }), - ({ ({ "scratch" }), "$agent_verb $target_name wickedly in the $limb " - "with $using." }) }), - // damage < 25 - ({ ({ ({ "jab" }), "$agent_verb $target_name in the $limb with $using." }), - ({ ({ "jab" }), "quickly $agent_verb $target_name in the $limb with " - "$using." }) }), - // damage < 30 - ({ ({ ({ "jab" }), "$agent_verb $target_name meanly in the $limb with " - "$using." }), - ({ ({ "jab" }), "$agent_verb $target_name solidly in the $limb with " - "$using." }) - // damage < 50 - ({ ({ ({ "cut" }), "$agent_verb $target_name pain - - - private mixed array MOVES = ({ - // baby moves - ({ ({ ({ "shake" }), "$agent_name $agent_verb oddly and " }), - ({ ({ "dance" }), "$agent_name $agent_verb and " }), - ({ ({ "shout" }), "$agent_name $agent_verb profanities and " }), - ({ ({ "sidestep" }), "$agent_name $agent_verb weakly and " }), - ({ ({ "blow" }), "$agent_name $agent_verb snot and " }), - ({ ({ "swing" }), "$agent_name $agent_verb blindly and " }), - ({ ({ "bellow" }), "$agent_name $agent_verb loudly and " }), - ({ ({ "see" }), "$agent_name $agent_verb an opening and " }), - ({ ({ "stumble" }), "$agent_name $agent_verb fortuitously and " }) }), - // better moves - ({ ({ ({ "grunt" }), "$agent_name $agent_verb angrily and " }), - ({ ({ "scream" }), "$agent_name $agent_verb \"Die!\", and " }), - ({ ({ "spit", "blow" }), "$agent_name $agent_verb, $agent_verb, and "}), - ({ ({ "slobber" }), "$agent_name $agent_verb evilly and " }), - ({ ({ "duck" }), "$agent_name $agent_verb and " }), - ({ ({ "rant" }), "$agent_name $agent_verb, \"Aaaarrrrggghhh!\" and " }), - ({ ({"glare"}), "$agent_name $agent_verb at $target_name evilly and "}), - ({ ({ "growl" }), "$agent_name $agent_verb menacingly and " }) }), - // awesome moves - ({ ({ ({ "rally" }), "$agent_name $agent_verb with determination and " }), - ({ ({ "lunge" }), "$agent_name $agent_verb quickly and " }), - ({ ({ "twirl" }), "$agent_name $agent_verb with finesse and " }), - ({ ({ "execute" }), "$agent_name $agent_verb a diving roll and " }), - ({ ({ "go" }), "$agent_name $agent_verb completely berserk and " }), - ({ ({ "whirl" }), "$agent_name $agent_verb blurringly and " }) }) }); - - mixed array GetMessages(string type) { - switch(type) { - case "blade": return BLADES; - case "blunt": return BLUNTS; - case "knife": return KNIVES; - case "projectile": return PROJECTILES; - default: return BLUNTS; - } - } - - mixed array GetMove(int amt) { - if( amt < 2 ) { - return 0; - } - amt = random(amt); - if( amt < 4 ) { - list = MOVES[0]; - } - else if( amt < 7 ) { - list = MOVES[1]; - } - else { - list = MOVES[2]; - } - return list[random(sizeof(list))]; - } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/command.c ds2.1/lib/daemon/command.c *** ds1.1/lib/daemon/command.c Sun Feb 1 21:30:01 1998 --- ds2.1/lib/daemon/command.c Wed Jul 5 00:00:58 2006 *************** *** 19,25 **** Commands = ([]); Paths = ({}); eventRehash( ({ DIR_PLAYER_CMDS, DIR_CREATOR_CMDS, ! DIR_SECURE_CREATOR_CMDS }) ); } void eventRehash(mixed paths) { --- 19,26 ---- Commands = ([]); Paths = ({}); eventRehash( ({ DIR_PLAYER_CMDS, DIR_CREATOR_CMDS, ! DIR_SECURE_PLAYER_CMDS, DIR_SECURE_CREATOR_CMDS, ! DIR_ADMIN_CMDS, DIR_SECURE_ADMIN_CMDS }) ); } void eventRehash(mixed paths) { *************** *** 38,44 **** if( pointerp(Commands[cmd]) ) Commands[cmd] += ({ path }); else Commands[cmd] = ({ path }); } ! Paths = distinct_array(Paths + ({ path })); } } --- 39,45 ---- if( pointerp(Commands[cmd]) ) Commands[cmd] += ({ path }); else Commands[cmd] = ({ path }); } ! Paths = singular_array( distinct_array(Paths + ({ path })) ); } } *************** *** 46,57 **** string *tmp; if( Commands[cmd] && sizeof(tmp = (path & (string *)Commands[cmd])) ) ! return sprintf("%s/%s", tmp[0], cmd); else { ! tmp = (path & Paths); ! if( sizeof(tmp = path - tmp) ) eventRehash(tmp); ! if( Commands[cmd] && sizeof(tmp = (path & (string *)Commands[cmd])) ) ! return sprintf("%s/%s", tmp[0], cmd); } return 0; } --- 47,58 ---- string *tmp; if( Commands[cmd] && sizeof(tmp = (path & (string *)Commands[cmd])) ) ! return sprintf("%s/%s", tmp[0], cmd); else { ! tmp = (path & Paths); ! if( sizeof(tmp = path - tmp) ) eventRehash(tmp); ! if( Commands[cmd] && sizeof(tmp = (path & (string *)Commands[cmd])) ) ! return sprintf("%s/%s", tmp[0], cmd); } return 0; } *************** *** 63,69 **** if( !path ) return keys(Commands); tmp = ({ }); foreach( cmd, paths in Commands) ! if( member_array(path, paths) != -1 ) tmp += ({ cmd }); return tmp; } --- 64,70 ---- if( !path ) return keys(Commands); tmp = ({ }); foreach( cmd, paths in Commands) ! if( member_array(path, paths) != -1 ) tmp += ({ cmd }); return tmp; } diff -c -r --new-file ds1.1/lib/daemon/decay.c ds2.1/lib/daemon/decay.c *** ds1.1/lib/daemon/decay.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/daemon/decay.c Tue Jul 11 18:30:58 2006 *************** *** 0 **** --- 1,25 ---- + #include <lib.h> + + inherit LIB_DAEMON; + + void eventDecay(); + + static void create() { + daemon::create(); + SetNoClean(1); + call_out((: eventDecay :), 30); + } + + static void eventDecay() { + object *limbs = filter(findobs(LIB_LIMB), (: clonep($1) :) ); + object *corpses = filter(findobs(LIB_CORPSE), (: clonep($1) :) ); + + corpses += find_inheritors(LIB_CORPSE); + limbs += find_inheritors(LIB_LIMB); + + limbs->eventDecay(); + corpses->eventDecay(); + + call_out((: eventDecay :), 30); + return; + } diff -c -r --new-file ds1.1/lib/daemon/domains.c ds2.1/lib/daemon/domains.c *** ds1.1/lib/daemon/domains.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/domains.c Wed Jul 5 00:00:58 2006 *************** *** 1,5 **** /* /daemon/domains.c ! * From the Dead Souls V Object Library * A daemon for handling domain stat information * Created by Descartes of Borg 961110 * Version: %A% --- 1,5 ---- /* /daemon/domains.c ! * From the Dead Souls Object Library * A daemon for handling domain stat information * Created by Descartes of Borg 961110 * Version: %A% diff -c -r --new-file ds1.1/lib/daemon/economy.c ds2.1/lib/daemon/economy.c *** ds1.1/lib/daemon/economy.c Sun Feb 1 21:30:01 1998 --- ds2.1/lib/daemon/economy.c Wed Dec 31 19:00:00 1969 *************** *** 1,57 **** - // /daemon/mudlib/economy_d.c - // from the Dead Souls Mudlib - // a daemon to handle currenciy inflation - // created by Descartes of Borg 931114 - - #include <lib.h> - #include <privs.h> - #include <save.h> - #include <clock.h> - - inherit LIB_DAEMON; - - private mapping Currencies; - int LastInflation; - - void create() { - string *borg; - float temps, tmp; - int i; - - daemon::create(); - SetNoClean(1); - Currencies = ([]); - restore_object(SAVE_ECONOMY); - i = sizeof(borg = keys(Currencies)); - temps = percent(time()-LastInflation, YEAR)* 0.01; - while(i--) { - tmp = temps * Currencies[borg[i]]["inflation"]; - Currencies[borg[i]]["rate"] += tmp*Currencies[borg[i]]["rate"]; - } - LastInflation = time(); - save_object(SAVE_ECONOMY); - } - - void add_currency(string type, float rate, float infl, float wt) { - if(!((int)master()->valid_apply(({ PRIV_CMDS })))) return; - if(!mapp(Currencies)) Currencies = ([]); - if(!type || !rate || !infl || !wt || Currencies[type]) return; - Currencies[type] = ([ "rate":rate, "inflation":infl, "weight":wt ]); - save_object(SAVE_ECONOMY); - } - - void change_currency(string type, string key, float x) { - if(!((int)master()->valid_apply( ({ PRIV_CMDS }) ))) return; - if(!mapp(Currencies)) Currencies = ([]); - if(!type || !Currencies[type] || !key || !x) return; - if(!Currencies[type][key]) return; - Currencies[type][key] = x; - save_object(SAVE_ECONOMY); - } - - float __Query(string type, string key) { - if(!Currencies[type]) return 0.0; - else return Currencies[type][key]; - } - - string *__QueryCurrencies() { return keys(Currencies); } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/help.c ds2.1/lib/daemon/help.c *** ds1.1/lib/daemon/help.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/help.c Tue Jul 11 18:30:59 2006 *************** *** 1,5 **** /* /verbs/common/help.c ! * from the Dead Soulsr2 Object Library * created by Descartes of Borg 951021 * Version: @(#) help.c 1.15@(#) * Last Modified: 96/12/14 --- 1,5 ---- /* /verbs/common/help.c ! * from the Dead Souls Object Library * created by Descartes of Borg 951021 * Version: @(#) help.c 1.15@(#) * Last Modified: 96/12/14 *************** *** 30,71 **** int CanAccess(object who, string index) { switch(index) { case "admin commands": ! return archp(who); case "creator commands": case "creator documents": case "library objects": case "daemon objects": ! return creatorp(who); default: ! return 1; } } ! static private void LoadIndices() { string array tmp; function f; string dir; ! f = function(string str) { return str[0..<3]; }; Indices = ([]); tmp = get_dir(DIR_ADMIN_VERBS + "/*.c") + get_dir(DIR_ADMIN_CMDS + "/*.c") ! + get_dir(DIR_SECURE_ADMIN_CMDS + "/*.c"); Indices["admin commands"] = map(tmp, f); tmp = get_dir(DIR_COMMON_VERBS+"/*.c") + ! get_dir(DIR_COMMON_CMDS + "/*.c") + ! get_dir(DIR_SECURE_COMMON_CMDS + "/*.c") + ! get_dir(DIR_ITEM_VERBS + "/*.c") + ! get_dir(DIR_PLAYER_VERBS+"/*.c") + ! get_dir(DIR_PLAYER_CMDS+"/*.c") + ! get_dir(DIR_ROOM_VERBS + "/*.c") + ! get_dir(DIR_SPELL_VERBS + "/*.c") + ! get_dir(DIR_SECURE_PLAYER_CMDS + "/*.c"); Indices["commands"] = map(tmp, f); tmp = get_dir(DIR_CREATOR_VERBS+"/*.c") + get_dir(DIR_CREATOR_CMDS+"/*.c") ! + get_dir(DIR_SECURE_CREATOR_CMDS + "/*.c"); Indices["creator commands"] = map(tmp, f); tmp = get_dir(DIR_UNDEAD_VERBS "/*.c"); --- 30,71 ---- int CanAccess(object who, string index) { switch(index) { case "admin commands": ! return archp(who); case "creator commands": case "creator documents": case "library objects": case "daemon objects": ! return creatorp(who); default: ! return 1; } } ! static private void LoadIndices() { string array tmp; function f; string dir; ! f = function(string str) { return str[0..<3]; }; Indices = ([]); tmp = get_dir(DIR_ADMIN_VERBS + "/*.c") + get_dir(DIR_ADMIN_CMDS + "/*.c") ! + get_dir(DIR_SECURE_ADMIN_CMDS + "/*.c"); Indices["admin commands"] = map(tmp, f); tmp = get_dir(DIR_COMMON_VERBS+"/*.c") + ! get_dir(DIR_COMMON_CMDS + "/*.c") + ! get_dir(DIR_SECURE_COMMON_CMDS + "/*.c") + ! get_dir(DIR_ITEM_VERBS + "/*.c") + ! get_dir(DIR_PLAYER_VERBS+"/*.c") + ! get_dir(DIR_PLAYER_CMDS+"/*.c") + ! get_dir(DIR_ROOM_VERBS + "/*.c") + ! get_dir(DIR_SPELL_VERBS + "/*.c") + ! get_dir(DIR_SECURE_PLAYER_CMDS + "/*.c"); Indices["commands"] = map(tmp, f); tmp = get_dir(DIR_CREATOR_VERBS+"/*.c") + get_dir(DIR_CREATOR_CMDS+"/*.c") ! + get_dir(DIR_SECURE_CREATOR_CMDS + "/*.c"); Indices["creator commands"] = map(tmp, f); tmp = get_dir(DIR_UNDEAD_VERBS "/*.c"); *************** *** 73,496 **** tmp = SOUL_D->GetEmotes(); Indices["feelings"] = tmp; - - tmp = filter(map(get_dir(DIR_SPELLS "/*.c"), - function(string file) { - file = DIR_SPELLS "/" + file; - if( file->GetVerb() == "cast" ) { - return file->GetSpell(); - } - return 0; - }), (: $1 :)); - Indices["spells"] = tmp; tmp = filter(map(get_dir(DIR_SPELLS "/*.c"), ! function(string file) { ! file = DIR_SPELLS "/" + file; ! if( file->GetVerb() == "pray" ) { ! return file->GetSpell(); ! } ! return 0; ! }), (: $1 :)); ! Indices["prayers"] = tmp; ! ! if( tmp = get_dir(DIR_PLAYER_HELP + "/") ) ! Indices["player documents"] = tmp + ({ "soul" }); ! else Indices["player documents"] = ({ "soul" }); ! ! if( tmp = get_dir(DIR_CREATOR_HELP "/") ) ! Indices["creator documents"] = tmp; ! else Indices["creator document"] = ({}); ! ! if( tmp = (string array)CLASSES_D->GetClasses() ) ! Indices["classes"] = tmp; ! else Indices["classes"] = ({}); ! ! if( tmp = (string array)RACES_D->GetRaces(1) ) ! Indices["races"] = tmp; ! else Indices["races"] = ({}); ! ! if( tmp = get_dir(DIR_LAW_HELP "/") ) ! Indices["law"] = tmp; ! else Indices["law"] = ({}); ! ! if( tmp = get_dir(DIR_RELIGION_HELP "/") ) ! Indices["religion"] = tmp; ! else Indices["religion"] = ({}); ! ! Indices["library objects"] = ({}); ! foreach(dir in ({ DIR_LIB, DIR_SECURE_LIB })){ ! if( !(tmp = get_dir(dir + "/*.c")) ) continue; ! else Indices["library objects"] += ! map(tmp, (: $(dir)+"/"+$1[0..<3] :)); ! } ! ! Indices["daemon objects"] = ({}); ! foreach(dir in ({ DIR_DAEMONS, DIR_SECURE_DAEMONS })) { ! if( !(tmp = get_dir(dir + "/*.c")) ) continue; ! else Indices["daemon objects"] += ! map(tmp, (: $(dir)+"/"+$1[0..<3] :)); } - } ! string GetHelp(string str) { ! string *tmp; ! string topic; ! int x; ! ! Error = 0; ! if( !str || str == "" || str == "help" ) { ! return ("Syntax: <help>\n" " <help index>\n" " <help TOPIC>\n" " <help INDEX TOPIC>\n\n" ! "Without an argument, you get this help screen. The same " ! "applies for trying to get help on the help command. With " ! "an argument, you are given information on the topic you " ! "specified. The special topic, \"help index\", puts you into " ! "a menu driven index of categories for which help exists. In " ! "some cases, the same help topic will exist in two separate " ! "categories. If help tells you that you have asked for " ! "help on such a topic, you may specify the index from which " ! "it comes by using the index name help gives you. For " ! "example:\n" ! "> help list\n" ! "There exists help for \"list\" in the following indices:\n" ! "commands, channels\n" ! ">\n" ! "You could then type \"help player commands list\" to get " ! "the help for the list player command.\n\n" ! "In general, most commands have only a single index, so there " ! "is generally no need to specify the index.\n" ! "Finally, to help you better understand how to issue commands " ! "on Dead Souls, you should check out the document " ! "\"help syntax\".\n\n" ! "See also: faq, index, syntax"); ! } ! if( sscanf(str, "adverbs %s", topic) || str == "adverbs" ) { ! return (string)SOUL_D->GetHelp(str); ! } ! tmp = GetIndices(str); ! if( sizeof(tmp) == 1 ) { ! return GetHelpByIndex(tmp[0], str); ! } ! else if( sizeof(tmp) > 1 ) { ! Error = "There exists help for \"" + str + "\" under the following " ! "indices:\n" + implode(tmp, ", "); ! return 0; ! } ! topic = ""; ! str = trim(str); ! while( (x = strsrch(str, " ")) != -1 ) { ! if( topic != "" ) { ! topic = topic + " " + str[0..(x-1)]; ! } ! else { ! topic = str[0..(x-1)]; ! } ! str = str[(x+1)..]; ! if( Indices[topic] && strlen(str) ) { ! return GetHelpByIndex(topic, str); ! } ! } ! Error = "Help for the topic \"" + str + "\" could not be found."; ! return 0; ! } ! ! string GetHelpByIndex(string index, string topic) { ! mixed array tmparr, fun; ! mapping tmpmap; ! object ob; ! string help, file, tmpstr; ! ! if( this_player() && !CanAccess(this_player(), index) ) { ! Error = "You do not have access to that information."; ! return 0; ! } ! switch(index) { ! case "admin commands": case "creator commands": case "undead commands": ! case "commands": ! switch(index) { ! case "admin commands": ! if( file_exists( DIR_ADMIN_VERBS + "/" + topic + ".c") ) ! file = DIR_ADMIN_VERBS + "/" + topic; ! else if( file_exists( DIR_ADMIN_CMDS + "/" + topic + ".c") ) ! file = DIR_ADMIN_CMDS + "/" + topic; ! else file = DIR_SECURE_ADMIN_CMDS + "/" + topic; ! break; ! ! case "creator commands": ! if( file_exists( DIR_CREATOR_VERBS + "/" + topic + ".c") ) ! file = DIR_CREATOR_VERBS + "/" + topic; ! else if( file_exists(DIR_CREATOR_CMDS + "/" + topic + ".c") ) ! file = DIR_CREATOR_CMDS + "/" + topic; ! else file = DIR_SECURE_CREATOR_CMDS + "/" + topic; ! break; ! ! case "commands": ! foreach(string directory in ({ DIR_COMMON_VERBS, ! DIR_COMMON_CMDS, ! DIR_SECURE_COMMON_CMDS, ! DIR_ITEM_VERBS, ! DIR_PLAYER_VERBS, ! DIR_PLAYER_CMDS, ! DIR_SECURE_PLAYER_CMDS, ! DIR_ROOM_VERBS, ! DIR_SPELL_VERBS })) { ! if( file_exists(directory + "/" + topic + ".c") ) { ! file = directory + "/" + topic; ! break; ! } ! } ! break; ! ! case "undead commands": ! file = DIR_UNDEAD_VERBS + "/" + topic; ! break; ! } ! if( !file_exists(file + ".c") ) { ! Error = "No such " + index[0..<2] + " exists."; ! return 0; ! } ! if( catch(help = file->GetHelp(topic)) ) { ! Error = "An error occurred in attempting to access help."; ! return 0; ! } ! if( !help ) { ! string *syn, *pd; ! string line; ! ! pd = regexp(explode(parse_dump(), "\n"), file[1..]); ! syn = ({}); ! foreach(line in pd) { ! sscanf(line, "%*s"+file[1..]+") %s", tmpstr); ! syn += ({ tmpstr }); ! } ! if( !sizeof(syn) ) { ! if( function_exists("help", load_object(file)) ) { ! Error = "This help may be out of date."; ! file->help(); ! return 0; ! } ! Error = "Unable to locate any syntax information on " + ! topic + "."; ! return 0; ! } ! help = "Syntax: " + topic + " " + syn[0] + "\n"; ! if( sizeof(syn) == 1 ) help += "\n"; ! else { ! foreach(line in syn[1..]) ! help += " " + topic + " " + line + "\n"; ! help += "\n"; ! } ! help += "No detailed documentation exists for this command."; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "player documents": case "creator documents": ! case "law": ! switch(index) { ! case "player documents": ! if( topic == "soul" ) { ! help = SOUL_D->GetHelp("soul"); ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! } ! file = DIR_PLAYER_HELP "/" + topic; ! break; ! ! case "creator documents": ! file = DIR_CREATOR_HELP "/" + topic; ! break; ! ! case "law": ! file = DIR_LAW_HELP "/" + topic; ! break; ! } ! if( !file_exists(file) ) { ! Error = "No such " + index[0..<2] + " is available."; ! return 0; ! } ! if( !(help = read_file(file)) ) { ! Error = "The document " + topic + " was empty."; ! return 0; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "feelings": ! help = SOUL_D->GetHelp(topic); ! if( !help ) { ! Error = "No such " + index[0..<2] + " is available."; ! return 0; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help;; ! ! case "library objects": ! topic = GetTopic(index, topic); ! if( catch(help = topic->GetHelp(topic)) ) { ! Error = "An error occurred in attempting to access help."; ! return 0; ! } ! if( !help ) { ! help = "No synopsis available for this object.\n\n"; ! } ! else { ! help = "Synopsis:\n" + help + "\n\n"; ! } ! tmparr = stat(topic + ".c"); ! tmpstr = "Object: " + topic + "\n" ! "Last Modified: " + ctime(tmparr[1]) + "\n"; ! if( tmparr[2] ) { ! tmpstr += "Last Loaded: " + ctime(tmparr[2]) + "\n\n"; ! } ! tmparr = inherit_list(ob = find_object(topic)); ! if( !sizeof(tmparr) ) { ! tmpstr += "No inherited objects\n\n"; ! } ! else { ! tmpstr += "Inherits:\n" + format_page(tmparr, 4) + "\n"; ! } ! tmparr = functions(ob, 1); ! tmpmap = ([]); ! foreach(fun in tmparr) { ! if( function_exists(fun[0], ob) != topic ) { ! continue; ! } ! if( fun[0] == "#global_init#" ) { ! continue; ! } ! if( tmpmap[fun[0]] ) { ! continue; ! } ! else { ! tmpmap[fun[0]] = ([ "type" : fun[2], ! "args" : (fun[1] ? fun[3..] : ({})) ]); ! } ! } ! help = tmpstr + help; ! if( !sizeof(tmparr) ) { ! help += "No functions\n\n"; ! } ! else { ! string fnc; ! ! help += "Functions:\n"; ! tmparr = sort_array(keys(tmpmap), 1); ! foreach(fnc in tmparr) { ! help += tmpmap[fnc]["type"] + fnc + "(" + ! implode(tmpmap[fnc]["args"], ", ") + ")\n"; ! } ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "daemon objects": ! topic = GetTopic(index, topic); ! if( catch(help = topic->GetHelp(topic)) ) { ! Error = "An error occurred in attempting to access help."; ! return 0; ! } ! if( !help ) { ! help = "No synopsis available for this object.\n\n"; ! } ! else { ! help = "Synopsis:\n" + help + "\n\n"; ! } ! tmparr = stat(topic + ".c"); ! tmpstr = "Object: " + topic + "\n" ! "Last Modified: " + ctime(tmparr[1]) + "\n"; ! if( tmparr[2] ) tmpstr += "Last Loaded: " + ctime(tmparr[2]) + "\n\n"; ! tmparr = inherit_list(ob = find_object(topic)); ! if( !sizeof(tmparr) ) tmpstr += "No inherited objects\n\n"; ! else tmpstr += "Inherits:\n" + format_page(tmparr, 4) + "\n"; ! tmparr = functions(ob, 1); ! tmpmap = ([]); ! foreach(fun in tmparr) { ! if( function_exists(fun[0], ob) != topic ) continue; ! if( fun[0] == "#global_init#" ) continue; ! if( tmpmap[fun[0]] ) continue; ! else tmpmap[fun[0]] = ([ "type" : fun[2], ! "args" : (fun[1] ? fun[3..] : ({})) ]); ! } ! help = tmpstr + help; ! if( !sizeof(tmparr) ) help += "No functions\n\n"; ! else { ! string fnc; ! ! help += "Functions:\n"; ! tmparr = sort_array(keys(tmpmap), 1); ! foreach(fnc in tmparr) ! help += tmpmap[fnc]["type"] + fnc + "(" + ! implode(tmpmap[fnc]["args"], ", ") + ")\n"; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "religons": case "religion": ! if( file_exists(DIR_RELIGION_HELP "/" + topic) ) { ! help = read_file(DIR_RELIGION_HELP "/" + topic); ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! } ! Error = "No such religion exists."; ! return 0; ! ! case "races": ! if( help = (string)RACES_D->GetHelp(topic) ) { ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! if( file_exists(DIR_RACE_HELP + "/" + topic) ) ! help += read_file(DIR_RACE_HELP + "/" + topic); ! return help; ! } ! Error = "No such race exists."; ! return 0; ! ! case "spells": case "prayers": ! ob = SPELLS_D->GetSpell(topic); ! if( !ob ) { ! Error = "No such spell exists."; ! return 0; ! } ! if( !(help = ob->GetHelp(topic)) ) { ! Error = "No help is available for that spell."; ! return 0; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "classes": ! if( help = (string)CLASSES_D->GetHelp(topic) ) { ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! if( file_exists(DIR_CLASS_HELP + "/" + topic) ) ! help += read_file(DIR_CLASS_HELP + "/" + topic); ! return help; ! } ! Error = "No such class exists."; ! return 0; ! ! default: ! Error = "No help exists for the index " + index + "."; ! return 0; ! } } varargs string array GetIndices(string topic) { string array topics, val; string ind, tmp; ! if( !topic ) { return sort_array(keys(Indices), 1); } --- 73,482 ---- tmp = SOUL_D->GetEmotes(); Indices["feelings"] = tmp; tmp = filter(map(get_dir(DIR_SPELLS "/*.c"), ! function(string file) { ! file = DIR_SPELLS "/" + file; ! if( file->GetVerb() == "cast" ) { ! return file->GetSpell(); ! } ! return 0; ! }), (: $1 :)); ! Indices["spells"] = tmp; ! ! tmp = filter(map(get_dir(DIR_SPELLS "/*.c"), ! function(string file) { ! file = DIR_SPELLS "/" + file; ! if( file->GetVerb() == "pray" ) { ! return file->GetSpell(); ! } ! return 0; ! }), (: $1 :)); ! Indices["prayers"] = tmp; ! ! if( tmp = get_dir(DIR_PLAYER_HELP + "/") ) ! Indices["player documents"] = tmp + ({ "soul" }); ! else Indices["player documents"] = ({ "soul" }); ! ! if( tmp = get_dir(DIR_CREATOR_HELP "/") ) ! Indices["creator documents"] = tmp; ! else Indices["creator document"] = ({}); ! ! if( tmp = (string array)CLASSES_D->GetClasses() ) ! Indices["classes"] = tmp; ! else Indices["classes"] = ({}); ! ! if( tmp = (string array)RACES_D->GetRaces(1) ) ! Indices["races"] = tmp; ! else Indices["races"] = ({}); ! ! if( tmp = get_dir(DIR_LAW_HELP "/") ) ! Indices["law"] = tmp; ! else Indices["law"] = ({}); ! ! if( tmp = get_dir(DIR_RELIGION_HELP "/") ) ! Indices["religion"] = tmp; ! else Indices["religion"] = ({}); ! ! Indices["library objects"] = ({}); ! foreach(dir in ({ DIR_LIB, DIR_SECURE_LIB })){ ! if( !(tmp = get_dir(dir + "/*.c")) ) continue; ! else Indices["library objects"] += ! map(tmp, (: $(dir)+"/"+$1[0..<3] :)); ! } ! ! Indices["daemon objects"] = ({}); ! foreach(dir in ({ DIR_DAEMONS, DIR_SECURE_DAEMONS })) { ! if( !(tmp = get_dir(dir + "/*.c")) ) continue; ! else Indices["daemon objects"] += ! map(tmp, (: $(dir)+"/"+$1[0..<3] :)); ! } } ! string GetHelp(string str) { ! string *tmp; ! string topic; ! int x; ! ! Error = 0; ! if( !str || str == "" || str == "help" ) { ! return ("Syntax: <help>\n" " <help index>\n" " <help TOPIC>\n" " <help INDEX TOPIC>\n\n" ! "The special topic, \"help index\", puts you into " ! "a menu driven index of categories for which help exists.\n\n" ! "For players, \"help commands\" will provide an index of " ! "available player commands.\n " ! "For creators, \"help creator commands\" provides an " ! "index of available creator commands.\n\n " ! "Try \"help commands\" " ! "and \"help creator commands\" first. \n\n" ! " "); ! } ! if( sscanf(str, "adverbs %s", topic) || str == "adverbs" ) { ! return (string)SOUL_D->GetHelp(str); ! } ! tmp = GetIndices(str); ! if( sizeof(tmp) == 1 ) { ! return GetHelpByIndex(tmp[0], str); ! } ! else if( sizeof(tmp) > 1 ) { ! Error = "There exists help for \"" + str + "\" under the following " ! "indices:\n" + implode(tmp, ", "); ! return 0; ! } ! topic = ""; ! str = trim(str); ! while( (x = strsrch(str, " ")) != -1 ) { ! if( topic != "" ) { ! topic = topic + " " + str[0..(x-1)]; ! } ! else { ! topic = str[0..(x-1)]; ! } ! str = str[(x+1)..]; ! if( Indices[topic] && strlen(str) ) { ! return GetHelpByIndex(topic, str); ! } ! } ! Error = "Help for the topic \"" + str + "\" could not be found."; ! return 0; ! } ! ! string GetHelpByIndex(string index, string topic) { ! mixed array tmparr, fun; ! mapping tmpmap; ! object ob; ! string help, file, tmpstr; ! ! if( this_player() && !CanAccess(this_player(), index) ) { ! Error = "You do not have access to that information."; ! return 0; ! } ! switch(index) { ! case "admin commands": case "creator commands": case "undead commands": ! case "commands": ! switch(index) { ! case "admin commands": ! if( file_exists( DIR_ADMIN_VERBS + "/" + topic + ".c") ) ! file = DIR_ADMIN_VERBS + "/" + topic; ! else if( file_exists( DIR_ADMIN_CMDS + "/" + topic + ".c") ) ! file = DIR_ADMIN_CMDS + "/" + topic; ! else file = DIR_SECURE_ADMIN_CMDS + "/" + topic; ! break; ! ! case "creator commands": ! if( file_exists( DIR_CREATOR_VERBS + "/" + topic + ".c") ) ! file = DIR_CREATOR_VERBS + "/" + topic; ! else if( file_exists(DIR_CREATOR_CMDS + "/" + topic + ".c") ) ! file = DIR_CREATOR_CMDS + "/" + topic; ! else file = DIR_SECURE_CREATOR_CMDS + "/" + topic; ! break; ! ! case "commands": ! foreach(string directory in ({ DIR_COMMON_VERBS, ! DIR_COMMON_CMDS, ! DIR_SECURE_COMMON_CMDS, ! DIR_ITEM_VERBS, ! DIR_PLAYER_VERBS, ! DIR_PLAYER_CMDS, ! DIR_SECURE_PLAYER_CMDS, ! DIR_ROOM_VERBS, ! DIR_SPELL_VERBS })) { ! if( file_exists(directory + "/" + topic + ".c") ) { ! file = directory + "/" + topic; ! break; ! } ! } ! break; ! ! case "undead commands": ! file = DIR_UNDEAD_VERBS + "/" + topic; ! break; ! } ! if( !file_exists(file + ".c") ) { ! Error = "No such " + index[0..<2] + " exists."; ! return 0; ! } ! if( catch(help = file->GetHelp(topic)) ) { ! Error = "An error occurred in attempting to access help."; ! return 0; ! } ! if( !help ) { ! string *syn, *pd; ! string line; ! ! pd = regexp(explode(parse_dump(), "\n"), file[1..]); ! syn = ({}); ! foreach(line in pd) { ! sscanf(line, "%*s"+file[1..]+") %s", tmpstr); ! syn += ({ tmpstr }); ! } ! if( !sizeof(syn) ) { ! if( function_exists("help", load_object(file)) ) { ! Error = " "; ! file->help(); ! return 0; ! } ! Error = "Unable to locate any syntax information on " + ! topic + "."; ! return 0; ! } ! help = "Syntax: " + topic + " " + syn[0] + "\n"; ! if( sizeof(syn) == 1 ) help += "\n"; ! else { ! foreach(line in syn[1..]) ! help += " " + topic + " " + line + "\n"; ! help += "\n"; ! } ! help += "No detailed documentation exists for this command."; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "player documents": case "creator documents": ! case "law": ! switch(index) { ! case "player documents": ! if( topic == "soul" ) { ! help = SOUL_D->GetHelp("soul"); ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! } ! file = DIR_PLAYER_HELP "/" + topic; ! break; ! ! case "creator documents": ! file = DIR_CREATOR_HELP "/" + topic; ! break; ! ! case "law": ! file = DIR_LAW_HELP "/" + topic; ! break; ! } ! if( !file_exists(file) ) { ! Error = "No such " + index[0..<2] + " is available."; ! return 0; ! } ! if( !(help = read_file(file)) ) { ! Error = "The document " + topic + " was empty."; ! return 0; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "feelings": ! help = SOUL_D->GetHelp(topic); ! if( !help ) { ! Error = "No such " + index[0..<2] + " is available."; ! return 0; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help;; ! ! case "library objects": ! topic = GetTopic(index, topic); ! if( catch(help = topic->GetHelp(topic)) ) { ! Error = "An error occurred in attempting to access help."; ! return 0; ! } ! if( !help ) { ! help = "No synopsis available for this object.\n\n"; ! } ! else { ! help = "Synopsis:\n" + help + "\n\n"; ! } ! tmparr = stat(topic + ".c"); ! tmpstr = "Object: " + topic + "\n" ! "Last Modified: " + ctime(tmparr[1]) + "\n"; ! if( tmparr[2] ) { ! tmpstr += "Last Loaded: " + ctime(tmparr[2]) + "\n\n"; ! } ! tmparr = inherit_list(ob = find_object(topic)); ! if( !sizeof(tmparr) ) { ! tmpstr += "No inherited objects\n\n"; ! } ! else { ! tmpstr += "Inherits:\n" + format_page(tmparr, 4) + "\n"; ! } ! tmparr = functions(ob, 1); ! tmpmap = ([]); ! foreach(fun in tmparr) { ! if( function_exists(fun[0], ob) != topic ) { ! continue; ! } ! if( fun[0] == "#global_init#" ) { ! continue; ! } ! if( tmpmap[fun[0]] ) { ! continue; ! } ! else { ! tmpmap[fun[0]] = ([ "type" : fun[2], ! "args" : (fun[1] ? fun[3..] : ({})) ]); ! } ! } ! help = tmpstr + help; ! if( !sizeof(tmparr) ) { ! help += "No functions\n\n"; ! } ! else { ! string fnc; ! ! help += "Functions:\n"; ! tmparr = sort_array(keys(tmpmap), 1); ! foreach(fnc in tmparr) { ! help += tmpmap[fnc]["type"] + fnc + "(" + ! implode(tmpmap[fnc]["args"], ", ") + ")\n"; ! } ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "daemon objects": ! topic = GetTopic(index, topic); ! if( catch(help = topic->GetHelp(topic)) ) { ! Error = "An error occurred in attempting to access help."; ! return 0; ! } ! if( !help ) { ! help = "No synopsis available for this object.\n\n"; ! } ! else { ! help = "Synopsis:\n" + help + "\n\n"; ! } ! tmparr = stat(topic + ".c"); ! tmpstr = "Object: " + topic + "\n" ! "Last Modified: " + ctime(tmparr[1]) + "\n"; ! if( tmparr[2] ) tmpstr += "Last Loaded: " + ctime(tmparr[2]) + "\n\n"; ! tmparr = inherit_list(ob = find_object(topic)); ! if( !sizeof(tmparr) ) tmpstr += "No inherited objects\n\n"; ! else tmpstr += "Inherits:\n" + format_page(tmparr, 4) + "\n"; ! tmparr = functions(ob, 1); ! tmpmap = ([]); ! foreach(fun in tmparr) { ! if( function_exists(fun[0], ob) != topic ) continue; ! if( fun[0] == "#global_init#" ) continue; ! if( tmpmap[fun[0]] ) continue; ! else tmpmap[fun[0]] = ([ "type" : fun[2], ! "args" : (fun[1] ? fun[3..] : ({})) ]); ! } ! help = tmpstr + help; ! if( !sizeof(tmparr) ) help += "No functions\n\n"; ! else { ! string fnc; ! ! help += "Functions:\n"; ! tmparr = sort_array(keys(tmpmap), 1); ! foreach(fnc in tmparr) ! help += tmpmap[fnc]["type"] + fnc + "(" + ! implode(tmpmap[fnc]["args"], ", ") + ")\n"; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "religons": case "religion": ! if( file_exists(DIR_RELIGION_HELP "/" + topic) ) { ! help = read_file(DIR_RELIGION_HELP "/" + topic); ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! } ! Error = "No such religion exists."; ! return 0; ! ! case "races": ! if( help = (string)RACES_D->GetHelp(topic) ) { ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! if( file_exists(DIR_RACE_HELP + "/" + topic) ) ! return help; ! } ! Error = "No such race exists."; ! return 0; ! ! case "spells": case "prayers": ! ob = SPELLS_D->GetSpell(topic); ! if( !ob ) { ! Error = "No such spell exists."; ! return 0; ! } ! if( !(help = ob->GetHelp(topic)) ) { ! Error = "No help is available for that spell."; ! return 0; ! } ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! return help; ! ! case "classes": ! if( help = (string)CLASSES_D->GetHelp(topic) ) { ! help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + ! "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; ! if( file_exists(DIR_CLASS_HELP + "/" + topic) ) ! help += read_file(DIR_CLASS_HELP + "/" + topic); ! return help; ! } ! Error = "No such class exists."; ! return 0; ! ! default: ! Error = "No help exists for the index " + index + "."; ! return 0; ! } } varargs string array GetIndices(string topic) { string array topics, val; string ind, tmp; ! if( !topic ) { return sort_array(keys(Indices), 1); } *************** *** 510,516 **** string GetTopic(string index, string topic) { string array dirlist; string dir; ! if( index != "library objects" && index != "daemon objects" ) { return topic; } --- 496,502 ---- string GetTopic(string index, string topic) { string array dirlist; string dir; ! if( index != "library objects" && index != "daemon objects" ) { return topic; } diff -c -r --new-file ds1.1/lib/daemon/include/classes.h ds2.1/lib/daemon/include/classes.h *** ds1.1/lib/daemon/include/classes.h Sun Feb 1 21:29:58 1998 --- ds2.1/lib/daemon/include/classes.h Wed Jul 5 00:01:03 2006 *************** *** 4,15 **** class Skill { int SkillClass; int Average; ! }; class Class { int Complete; mapping Multis; mapping Skills; ! }; #endif /* l_classes_h */ --- 4,15 ---- class Skill { int SkillClass; int Average; ! } class Class { int Complete; mapping Multis; mapping Skills; ! } #endif /* l_classes_h */ diff -c -r --new-file ds1.1/lib/daemon/include/races.h ds2.1/lib/daemon/include/races.h *** ds1.1/lib/daemon/include/races.h Sun Feb 1 21:29:58 1998 --- ds2.1/lib/daemon/include/races.h Wed Jul 5 00:01:03 2006 *************** *** 4,10 **** class Stat { int Class; int Average; ! }; class Race { mixed array Limbs; --- 4,10 ---- class Stat { int Class; int Average; ! } class Race { mixed array Limbs; *************** *** 15,23 **** int Complete; int PlayerFlag; string Language; ! }; ! int GetArmour(string str); int GetResistance(string str); #endif /* l_races_h */ --- 15,24 ---- int Complete; int PlayerFlag; string Language; ! mapping Skills; ! } ! int GetArmor(string str); int GetResistance(string str); #endif /* l_races_h */ diff -c -r --new-file ds1.1/lib/daemon/include/stargate.h ds2.1/lib/daemon/include/stargate.h *** ds1.1/lib/daemon/include/stargate.h Wed Dec 31 19:00:00 1969 --- ds2.1/lib/daemon/include/stargate.h Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,18 ---- + #include "/include/stargate.h" + + #ifndef daemon_stargate_h + #define daemon_stargate_h + + void eventLoad(); + void eventSave(); + int SetStargate(string address, string destination); + int RemoveStargate(string address); + mapping GetStargates(); + int SetStatus(string address, string status); + string GetStatus(string address); + string GetDestination(string address); + string GetEndpoint(string address); + int eventConnect(string from, string to); + int eventDisconnect(string from); + + #endif diff -c -r --new-file ds1.1/lib/daemon/intermud.c ds2.1/lib/daemon/intermud.c *** ds1.1/lib/daemon/intermud.c Sun Feb 1 21:34:37 1998 --- ds2.1/lib/daemon/intermud.c Tue Jul 11 18:30:59 2006 *************** *** 11,16 **** --- 11,17 ---- #else #include <lib.h> + #include <privs.h> #include <save.h> #include <config.h> #include <daemons.h> *************** *** 31,37 **** Password = 0; Tries = 0; Banned = ([]); - Nameservers = ({ ({ "*gjs", "208.192.43.105 9000" }) }); MudList = new(class list); ChannelList = new(class list); MudList->ID = -1; --- 32,37 ---- *************** *** 39,51 **** ChannelList->ID = -1; ChannelList->List = ([]); if( file_size( SAVE_INTERMUD __SAVE_EXTENSION__ ) > 0 ) ! unguarded( (: restore_object, SAVE_INTERMUD, 1 :) ); SetNoClean(1); SetDestructOnClose(1); SetSocketType(MUD); ! call_out( (: Setup :), 2); } static void Setup() { string ip; int port; --- 39,57 ---- ChannelList->ID = -1; ChannelList->List = ([]); if( file_size( SAVE_INTERMUD __SAVE_EXTENSION__ ) > 0 ) ! unguarded( (: restore_object, SAVE_INTERMUD, 1 :) ); ! Nameservers = ({ ({ "*yatmim", "149.152.218.102 23" }) }); SetNoClean(1); + tn("INTERMUD_D reloaded."); SetDestructOnClose(1); SetSocketType(MUD); ! if(DISABLE_INTERMUD == 1){ ! call_out( (: eventDestruct :), 2); ! } ! else call_out( (: Setup :), 2); } + static void Setup() { string ip; int port; *************** *** 54,184 **** sscanf(Nameservers[0][1], "%s %d", ip, port); if( eventCreateSocket(ip, port) < 0 ) return; eventWrite( ({ "startup-req-3", 5, mud_name(), 0, Nameservers[0][0], 0, ! Password, MudList->ID, ChannelList->ID, query_host_port(), ! PORT_OOB, PORT_UDP, mudlib() + " " + mudlib_version(), ! mudlib() + " " + mudlib_version(), version(), "LPMud", ! MUD_STATUS, ADMIN_EMAIL, ! (mapping)SERVICES_D->GetServices(), ([]) }) ); } static void eventRead(mixed *packet) { - string *cles; mixed val; ! string ns, cle; ! int i, maxi; if( !packet || sizeof(packet) < 6 ) return; /* should send error */ if( Banned[packet[2]] ) { - string reason = Banned[packet[2]]; eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! "Your mud is not allowed to send to Dead Souls.", ! packet })); ! return; } switch(packet[0]) { ! case "startup-reply": ! if( sizeof(packet) != 8 ) return; /* should send error */ ! if( !sizeof(packet[6]) ) return; ! if( packet[6][0][0] == Nameservers[0][0] ) { ! Nameservers = packet[6]; ! Connected = Nameservers[0][0]; ! Password = packet[7]; ! save_object(SAVE_INTERMUD); ! } ! else { ! Nameservers = packet[6]; ! Setup(); ! } ! return; ! case "mudlist": ! if( sizeof(packet) != 8 ) return; ! if( packet[6] == MudList->ID ) return; ! if( packet[2] != Nameservers[0][0] ) return; ! MudList->ID = packet[6]; ! foreach(cle, val in packet[7]) { ! if( !val && MudList->List[cle] != 0 ) map_delete(MudList->List, cle); ! else if( val ) MudList->List[cle] = val; ! } ! save_object(SAVE_INTERMUD); ! return; ! case "channel-t": ! SERVICES_D->eventReceiveChannelTargettedEmote(packet); ! break; ! case "channel-e": ! SERVICES_D->eventReceiveChannelEmote(packet); ! break; ! case "channel-m": ! SERVICES_D->eventReceiveChannelMessage(packet); ! break; ! case "chan-who-reply": ! SERVICES_D->eventReceiveChannelWhoReply(packet); ! break; ! case "chan-who-req": ! SERVICES_D->eventReceiveChannelWhoRequest(packet); ! break; ! case "chan-user-req": ! SERVICES_D->eventReceiveChannelUserRequest(packet); ! break; ! case "chanlist-reply": ! // if( packet[6] == ChannelList->ID ) return; ! if( packet[2] != Nameservers[0][0] ) return; ! ChannelList->ID = packet[6]; ! foreach(cle, val in packet[7]) { ! if( !val && ChannelList->List != 0 ) map_delete(ChannelList->List, cle); ! else if( val ) ChannelList->List[cle] = val; ! } ! save_object(SAVE_INTERMUD); ! SERVICES_D->eventRegisterChannels(packet[7]); ! return; ! case "emoteto": ! SERVICES_D->eventReceiveEmote(packet); ! break; ! case "finger-req": ! SERVICES_D->eventReceiveFingerRequest(packet); ! break; ! case "finger-reply": ! SERVICES_D->eventReceiveFingerReply(packet); ! break; ! case "locate-req": ! SERVICES_D->eventReceiveLocateRequest(packet); ! break; ! case "locate-reply": ! SERVICES_D->eventReceiveLocateReply(packet); ! break; ! case "tell": ! SERVICES_D->eventReceiveTell(packet); ! break; ! case "chan-user-reply": ! case "ucache-update": ! SERVICES_D->eventReceiveUcacheUpdate(packet); ! break; ! case "who-req": ! SERVICES_D->eventReceiveWhoRequest(packet); ! break; ! case "who-reply": ! SERVICES_D->eventReceiveWhoReply(packet); ! break; ! case "news": ! SERVICES_D->eventReceiveNews(packet); ! break; ! case "mail": ! SERVICES_D->eventReceiveMail(packet); ! break; ! case "mail-ok": ! SERVICES_D->eventReceiveMailOk(packet); ! break; ! case "file": ! break; ! case "error": ! SERVICES_D->eventReceiveError(packet); ! break; ! default: ! break; } } --- 60,238 ---- sscanf(Nameservers[0][1], "%s %d", ip, port); if( eventCreateSocket(ip, port) < 0 ) return; eventWrite( ({ "startup-req-3", 5, mud_name(), 0, Nameservers[0][0], 0, ! Password, MudList->ID, ChannelList->ID, query_host_port(), ! PORT_OOB, PORT_UDP, mudlib() + " " + mudlib_version(), ! mudlib() + " " + mudlib_version(), version(), "LPMud", ! MUD_STATUS, ADMIN_EMAIL, ! (mapping)SERVICES_D->GetServices(), ([]) }) ); ! tn("INTERMUD_D setup: "+identify( ({ ! "startup-req-3", 5, mud_name(), 0, Nameservers[0][0], 0, ! Password, MudList->ID, ChannelList->ID, query_host_port(), ! PORT_OOB, PORT_UDP, mudlib() + " " + mudlib_version(), ! mudlib() + " " + mudlib_version(), version(), "LPMud", ! MUD_STATUS, ADMIN_EMAIL, ! (mapping)SERVICES_D->GetServices(), ([]) }) ), "red");; ! } ! ! void eventClearVars(){ ! if( !((int)master()->valid_apply(({ PRIV_ASSIST, INTERMUD_D }))) ) ! error("Illegal attempt to reset intermud: "+get_stack()+" "+identify(previous_object(-1))); ! Connected = 0; ! Tries = 0; ! MudList = new(class list); ! ChannelList = new(class list); ! MudList->ID = -1; ! MudList->List = ([]); ! ChannelList->ID = -1; ! ChannelList->List = ([]); ! save_object(SAVE_INTERMUD); } static void eventRead(mixed *packet) { mixed val; ! string cle; if( !packet || sizeof(packet) < 6 ) return; /* should send error */ if( Banned[packet[2]] ) { eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! "Your mud is not allowed to send to Dead Souls.", ! packet })); ! return; } switch(packet[0]) { ! case "startup-reply": ! log_file("intermud",identify(packet)); ! tn("INTERMUD_D: "+identify(packet),"red"); ! if( sizeof(packet) != 8 ) { ! tn("We don't like the mudlist packet size.","red"); ! return; ! } ! if( !sizeof(packet[6]) ) { ! tn("We don't like an absence of packet element 6.","red"); ! return; ! } ! if( packet[6][0][0] == Nameservers[0][0] ) { ! Nameservers = packet[6]; ! Connected = Nameservers[0][0]; ! Password = packet[7]; ! save_object(SAVE_INTERMUD); ! } ! else { ! Nameservers = packet[6]; ! Setup(); ! } ! return; ! case "mudlist": ! tn("INTERMUD_D mudlist received.","red"); ! log_file("mudlist_packet",identify(packet),1); ! if( sizeof(packet) != 8 ) { ! tn("We don't like the mudlist packet size.","red"); ! return; ! } ! if( packet[6] == MudList->ID ) { ! tn("We don't like packet element 6. It is: "+identify(packet[6]),"red"); ! tn("We will continue anyway.","red"); ! } ! if( packet[2] != Nameservers[0][0] ) { ! tn("We don't like packet element 2. It is: "+identify(packet[2]),"red"); ! return; ! } ! ! MudList->ID = packet[6]; ! foreach(cle, val in packet[7]) { ! if(cle) tn("Procesing cle: "+identify(cle),"cyan"); ! if(val) tn("Procesing val: "+identify(val)+"\n--\n","cyan"); ! if( !val && MudList->List[cle] != 0 ) map_delete(MudList->List, cle); ! else if( val ) MudList->List[cle] = val; ! } ! save_object(SAVE_INTERMUD); ! return; ! case "auth-mud-req": ! SERVICES_D->eventReceiveAuthRequest(packet); ! break; ! case "auth-mud-reply": ! SERVICES_D->eventReceiveAuthReply(packet); ! break; ! case "channel-t": ! SERVICES_D->eventReceiveChannelTargettedEmote(packet); ! break; ! case "channel-e": ! SERVICES_D->eventReceiveChannelEmote(packet); ! break; ! case "channel-m": ! SERVICES_D->eventReceiveChannelMessage(packet); ! break; ! case "chan-who-reply": ! SERVICES_D->eventReceiveChannelWhoReply(packet); ! break; ! case "chan-who-req": ! SERVICES_D->eventReceiveChannelWhoRequest(packet); ! break; ! case "chan-user-req": ! SERVICES_D->eventReceiveChannelUserRequest(packet); ! break; ! case "chanlist-reply": ! tn("chanlist reply: "+identify(packet), "blue"); ! if( packet[2] != Nameservers[0][0] ) return; ! ChannelList->ID = packet[6]; ! foreach(cle, val in packet[7]) { ! if( !val && ChannelList->List != 0 ) map_delete(ChannelList->List, cle); ! else if( val ) ChannelList->List[cle] = val; ! } ! save_object(SAVE_INTERMUD); ! SERVICES_D->eventRegisterChannels(packet[7]); ! return; ! case "emoteto": ! SERVICES_D->eventReceiveEmote(packet); ! break; ! case "finger-req": ! SERVICES_D->eventReceiveFingerRequest(packet); ! break; ! case "finger-reply": ! SERVICES_D->eventReceiveFingerReply(packet); ! break; ! case "locate-req": ! SERVICES_D->eventReceiveLocateRequest(packet); ! break; ! case "locate-reply": ! SERVICES_D->eventReceiveLocateReply(packet); ! break; ! case "tell": ! SERVICES_D->eventReceiveTell(packet); ! break; ! case "chan-user-reply": ! tn("INTERMUD_D: chan-user-reply received.","red"); ! case "ucache-update": ! SERVICES_D->eventReceiveUcacheUpdate(packet); ! break; ! case "who-req": ! SERVICES_D->eventReceiveWhoRequest(packet); ! break; ! case "who-reply": ! SERVICES_D->eventReceiveWhoReply(packet); ! break; ! case "news": ! SERVICES_D->eventReceiveNews(packet); ! break; ! case "mail": ! SERVICES_D->eventReceiveMail(packet); ! break; ! case "mail-ok": ! SERVICES_D->eventReceiveMailOk(packet); ! break; ! case "file": ! tn("INTERMUD_D: file packet received.","red"); ! break; ! case "error": ! SERVICES_D->eventReceiveError(packet); ! break; ! default: ! break; } } *************** *** 193,198 **** --- 247,253 ---- static void eventConnectionFailure() { if( Connected ) return; + tn("INTERMUD_D: CONNECTION FAILED","red"); error("Failed to find a useful name server.\n"); } *************** *** 206,248 **** if( MudList->List[mud] ) return mud; lc = map(uc = keys(MudList->List), function(string str) { ! if( !str ) return ""; ! else return lower_case(str); ! }); ! x = member_array(lower_case(mud), lc); ! if( x < 0 ) return 0; ! else return uc[x]; ! } ! ! mapping GetMudList() { return copy(MudList->List); } ! string *GetMuds() { return keys(MudList->List); } ! mapping GetChannelList() { return copy(ChannelList->List); } ! string *GetChannels() { return keys(ChannelList->List); } ! string *GetMatch(string mud) { ! string *uc, *lc; ! mud = lower_case(mud); ! lc = map(uc = keys(MudList->List), (: lower_case :)); ! return map(filter(regexp(lc, "^"+mud, 1), (: intp :)), (: $(uc)[$1] :)); ! } ! string GetNameserver() { return Nameservers[0][0]; } ! int AddBanned(string mud, string reason) { ! if( !master()->valid_apply(({})) ) { ! return 0; } - if( !(mud = GetMudName(mud)) ) { - return 0; - } - Banned[mud] = reason; - save_object(SAVE_INTERMUD); - return 1; - } #endif /* __PACKAGE_SOCKETS__ */ --- 261,315 ---- if( MudList->List[mud] ) return mud; lc = map(uc = keys(MudList->List), function(string str) { ! if( !str ) return ""; ! else return lower_case(str); ! }); ! x = member_array(lower_case(mud), lc); ! if( x < 0 ) return 0; ! else return uc[x]; ! } ! ! mapping GetMudList() { return copy(MudList->List); } ! ! string *GetMuds() { return keys(MudList->List); } ! ! string *GetLCMuds() { ! string *orig_arr, *new_arr; ! orig_arr = GetMuds(); ! new_arr = ({}); ! foreach(string namen in orig_arr){ ! new_arr += ({ lower_case(namen) }); ! } ! return new_arr; ! } ! mapping GetChannelList() { return copy(ChannelList->List); } ! string *GetChannels() { return keys(ChannelList->List); } ! string *GetMatch(string mud) { ! string *uc, *lc; ! mud = lower_case(mud); ! lc = map(uc = keys(MudList->List), (: lower_case :)); ! return map(filter(regexp(lc, "^"+mud, 1), (: intp :)), (: $(uc)[$1] :)); ! } ! string GetNameserver() { return Nameservers[0][0]; } ! mixed *GetNameservers() { return copy(Nameservers); } ! int AddBanned(string mud, string reason) { ! if( !master()->valid_apply(({})) ) { ! return 0; ! } ! if( !(mud = GetMudName(mud)) ) { ! return 0; ! } ! Banned[mud] = reason; ! save_object(SAVE_INTERMUD); ! return 1; } #endif /* __PACKAGE_SOCKETS__ */ diff -c -r --new-file ds1.1/lib/daemon/news.c ds2.1/lib/daemon/news.c *** ds1.1/lib/daemon/news.c Sun Feb 1 21:30:02 1998 --- ds2.1/lib/daemon/news.c Wed Jul 5 00:00:58 2006 *************** *** 17,36 **** s = stat(NEWS_GENERAL)[1]; if( s != (int)this_player()->GetNews("general") ) { string news; ! news = GetNews("general"); this_player()->SetNews("general", s); message("news", "\n%^RED%^General news:", this_player()); ! this_player()->eventPrint(news); ! message("prompt", "Press <return> to continue: ", this_player()); if( !((int)this_player()->GetClass()) && !creatorp(this_player()) ) ! input_to((: NewbieNews :)); else input_to((: ClassNews, "" :)); return; } } if( !((int)this_player()->GetClass()) && !creatorp(this_player()) ) ! NewbieNews(); else ClassNews(""); } --- 17,36 ---- s = stat(NEWS_GENERAL)[1]; if( s != (int)this_player()->GetNews("general") ) { string news; ! news = GetNews("general"); this_player()->SetNews("general", s); message("news", "\n%^RED%^General news:", this_player()); ! this_player()->eventPrint(news); ! message("prompt", "Press <return> to continue: ", this_player()); if( !((int)this_player()->GetClass()) && !creatorp(this_player()) ) ! input_to((: NewbieNews :)); else input_to((: ClassNews, "" :)); return; } } if( !((int)this_player()->GetClass()) && !creatorp(this_player()) ) ! NewbieNews(); else ClassNews(""); } *************** *** 52,82 **** if( !cl || cl == "" ) cl = "cleric"; else { switch(cl) { ! case "cleric": cl = "fighter"; break; ! case "fighter": cl = "fisher"; break; ! case "fisher": cl = "kataan"; break; ! ! case "kataan": cl = "mage"; break; ! case "mage": cl = "monk"; break; ! case "monk": cl = "rogue"; break; ! case "rogue": HighMortalNews(); return; } --- 52,82 ---- if( !cl || cl == "" ) cl = "cleric"; else { switch(cl) { ! case "cleric": cl = "fighter"; break; ! case "fighter": cl = "fisher"; break; ! case "fisher": cl = "kataan"; break; ! ! case "kataan": cl = "mage"; break; ! case "mage": cl = "monk"; break; ! case "monk": cl = "rogue"; break; ! case "rogue": HighMortalNews(); return; } *************** *** 91,97 **** news = GetNews(cl); this_player()->SetNews(cl, s); message("news", "\n%^RED%^" + capitalize(cl) + " news:", ! this_player()); message("news", news, this_player()); message("prompt", "Press <return> to continue: ", this_player()); input_to( (: ClassNews, cl :)); --- 91,97 ---- news = GetNews(cl); this_player()->SetNews(cl, s); message("news", "\n%^RED%^" + capitalize(cl) + " news:", ! this_player()); message("news", news, this_player()); message("prompt", "Press <return> to continue: ", this_player()); input_to( (: ClassNews, cl :)); *************** *** 108,114 **** s = stat(NEWS_HM)[1]; if( s != (int)this_player()->GetNews("hm") ) { string news; ! news = GetNews("hm"); this_player()->SetNews("hm", s); message("news", "\n%^RED%^High mortal news:", this_player()); --- 108,114 ---- s = stat(NEWS_HM)[1]; if( s != (int)this_player()->GetNews("hm") ) { string news; ! news = GetNews("hm"); this_player()->SetNews("hm", s); message("news", "\n%^RED%^High mortal news:", this_player()); *************** *** 128,134 **** s = stat(NEWS_AVATAR)[1]; if( s != (int)this_player()->GetNews("avatar") ) { string news; ! news = GetNews("avatar"); this_player()->SetNews("avatar", s); message("news", "\n%^RED%^Avatar news:", this_player()); --- 128,134 ---- s = stat(NEWS_AVATAR)[1]; if( s != (int)this_player()->GetNews("avatar") ) { string news; ! news = GetNews("avatar"); this_player()->SetNews("avatar", s); message("news", "\n%^RED%^Avatar news:", this_player()); *************** *** 148,154 **** s = stat(NEWS_CREATOR)[1]; if( s != (int)this_player()->GetNews("creator") ) { string news; ! news = GetNews("creator"); this_player()->SetNews("creator", s); message("news", "\n%^RED%^Creator news:", this_player()); --- 148,154 ---- s = stat(NEWS_CREATOR)[1]; if( s != (int)this_player()->GetNews("creator") ) { string news; ! news = GetNews("creator"); this_player()->SetNews("creator", s); message("news", "\n%^RED%^Creator news:", this_player()); *************** *** 168,174 **** s = stat(NEWS_ADMIN)[1]; if( s != (int)this_player()->GetNews("admin") ) { string news; ! news = GetNews("admin"); this_player()->SetNews("admin", s); message("news", "\n%^RED%^Admin news:", this_player()); --- 168,174 ---- s = stat(NEWS_ADMIN)[1]; if( s != (int)this_player()->GetNews("admin") ) { string news; ! news = GetNews("admin"); this_player()->SetNews("admin", s); message("news", "\n%^RED%^Admin news:", this_player()); *************** *** 187,219 **** string GetNews(string type) { string file; ! switch(type) { ! case "admin": file = NEWS_ADMIN; break; ! case "avatar": file = NEWS_AVATAR; break; ! case "creator": file = NEWS_CREATOR; break; ! case "general": file = NEWS_GENERAL; break; ! ! case "hm": file = NEWS_HM; break; ! case "newbie": file = NEWS_NEWBIE; break; ! default: file = DIR_NEWS "/" + type; break; } --- 187,219 ---- string GetNews(string type) { string file; ! switch(type) { ! case "admin": file = NEWS_ADMIN; break; ! case "avatar": file = NEWS_AVATAR; break; ! case "creator": file = NEWS_CREATOR; break; ! case "general": file = NEWS_GENERAL; break; ! ! case "hm": file = NEWS_HM; break; ! case "newbie": file = NEWS_NEWBIE; break; ! default: file = DIR_NEWS "/" + type; break; } diff -c -r --new-file ds1.1/lib/daemon/notify.c ds2.1/lib/daemon/notify.c *** ds1.1/lib/daemon/notify.c Sun Feb 1 21:30:02 1998 --- ds2.1/lib/daemon/notify.c Wed Jul 5 00:00:58 2006 *************** *** 2,47 **** * created by Blitz@Dead Souls 960115 * notification daemon which displays notices to all cres who login */ ! #include <lib.h> #include <save.h> #include "include/notify.h" ! inherit LIB_DAEMON; ! #define MaxTime (3600 * 24 * 60) ! private mixed * Notes; ! static void create() { int x; daemon::create(); SetNoClean(1); Notes = ({}); if( unguarded((: file_size(SAVE_NOTIFY __SAVE_EXTENSION__) :)) > 0 ) ! unguarded((: restore_object(SAVE_NOTIFY) :)); x = sizeof(Notes); while( sizeof(Notes) && (time() - Notes[0][Date]) > MaxTime ) ! Notes -= ({ Notes[0] }); if( x != sizeof(Notes) ) eventSaveNotices(); } ! static int eventSaveNotices() { if( !archp(this_player()) ) return 0; else return unguarded((: save_object(SAVE_NOTIFY) :)); } ! int eventAddNotice(object who, string msg) { object * obs; - int x = time(); if( !who || !sizeof(msg) ) return 0; Notes += ({ ({ time(), (string)who->GetName(), msg }) }); if( sizeof(obs = filter(users() - ({ who }), (: creatorp :))) ) ! obs->eventPrint("["+(string)who->GetName()+" added a new notice]"); if( eventSaveNotices() ) return (sizeof(Notes)); else return 0; } ! int eventRemoveNotice(int x) { mixed var = copy(Notes); if( x < 0 || x > sizeof(Notes) - 1 ) return 0; --- 2,46 ---- * created by Blitz@Dead Souls 960115 * notification daemon which displays notices to all cres who login */ ! #include <lib.h> #include <save.h> #include "include/notify.h" ! inherit LIB_DAEMON; ! #define MaxTime (3600 * 24 * 60) ! private mixed * Notes; ! static void create() { int x; daemon::create(); SetNoClean(1); Notes = ({}); if( unguarded((: file_size(SAVE_NOTIFY __SAVE_EXTENSION__) :)) > 0 ) ! unguarded((: restore_object(SAVE_NOTIFY) :)); x = sizeof(Notes); while( sizeof(Notes) && (time() - Notes[0][Date]) > MaxTime ) ! Notes -= ({ Notes[0] }); if( x != sizeof(Notes) ) eventSaveNotices(); } ! static int eventSaveNotices() { if( !archp(this_player()) ) return 0; else return unguarded((: save_object(SAVE_NOTIFY) :)); } ! int eventAddNotice(object who, string msg) { object * obs; if( !who || !sizeof(msg) ) return 0; Notes += ({ ({ time(), (string)who->GetName(), msg }) }); if( sizeof(obs = filter(users() - ({ who }), (: creatorp :))) ) ! obs->eventPrint("["+(string)who->GetName()+" added a new notice]"); if( eventSaveNotices() ) return (sizeof(Notes)); else return 0; } ! int eventRemoveNotice(int x) { mixed var = copy(Notes); if( x < 0 || x > sizeof(Notes) - 1 ) return 0; *************** *** 49,55 **** if( !eventSaveNotices() ) return (Notes = var), 0; else return 1; } ! int eventPrintNotices(object who, int start_time) { mixed str = ({ "[ %^YELLOW%^"+mud_name()+" Creator Notices %^RESET%^]", "" }); int y = sizeof(Notes); --- 48,54 ---- if( !eventSaveNotices() ) return (Notes = var), 0; else return 1; } ! int eventPrintNotices(object who, int start_time) { mixed str = ({ "[ %^YELLOW%^"+mud_name()+" Creator Notices %^RESET%^]", "" }); int y = sizeof(Notes); *************** *** 57,69 **** if( x < 0 || start_time > Notes[x][Date] ) return 0; while( x > 0 && Notes[x - 1][Date] > start_time ) x--; do str += ({ sprintf("%sAdded %s by %s [id #%d]:\n\t%s%s", ! "%^RESET%^", ctime(Notes[x][Date]), Notes[x][Author], x, ! "%^CYAN%^", Notes[x][Message]), "" }); while( ++x < y ); who->eventPage(str); return 1; } ! int eventWriteNotices(string file, int start_time) { string str = "Dead Souls Notices Text Dump.\n\n"; mixed var; --- 56,68 ---- if( x < 0 || start_time > Notes[x][Date] ) return 0; while( x > 0 && Notes[x - 1][Date] > start_time ) x--; do str += ({ sprintf("%sAdded %s by %s [id #%d]:\n\t%s%s", ! "%^RESET%^", ctime(Notes[x][Date]), Notes[x][Author], x, ! "%^CYAN%^", Notes[x][Message]), "" }); while( ++x < y ); who->eventPage(str); return 1; } ! int eventWriteNotices(string file, int start_time) { string str = "Dead Souls Notices Text Dump.\n\n"; mixed var; *************** *** 72,78 **** if( x < 0 || start_time > Notes[x][Date] ) return 0; while( x > 0 && Notes[x - 1][Date] > start_time ) x--; foreach(var in Notes[x..]) ! str += sprintf("Added %s by %s\n\t%s\n\n", ctime(var[Date]), ! var[Author], var[Message]); return write_file(file, str); } --- 71,77 ---- if( x < 0 || start_time > Notes[x][Date] ) return 0; while( x > 0 && Notes[x - 1][Date] > start_time ) x--; foreach(var in Notes[x..]) ! str += sprintf("Added %s by %s\n\t%s\n\n", ctime(var[Date]), ! var[Author], var[Message]); return write_file(file, str); } diff -c -r --new-file ds1.1/lib/daemon/party.c ds2.1/lib/daemon/party.c *** ds1.1/lib/daemon/party.c Sun Feb 1 21:30:03 1998 --- ds2.1/lib/daemon/party.c Wed Jul 5 00:00:58 2006 *************** *** 25,40 **** if( !(p = Parties[pname]) ) return "No such party exists."; if( p->Leader != who ) ! return "You must be the party leader in order to change leaders."; if( member_array(targ, p->Members) == -1 ) ! return (string)targ->GetName() + " is not in the party."; return 1; } mixed CanCreateParty(object who, string name) { if( Parties[name] ) return "A party by that name already exists."; if( member_array(name, (string *)CHAT_D->GetChannels()) != -1 ) ! return "You cannot use the name " + name + " for your party."; if( (string)who->GetParty() ) return "You are already in a party!"; return 1; } --- 25,40 ---- if( !(p = Parties[pname]) ) return "No such party exists."; if( p->Leader != who ) ! return "You must be the party leader in order to change leaders."; if( member_array(targ, p->Members) == -1 ) ! return (string)targ->GetName() + " is not in the party."; return 1; } mixed CanCreateParty(object who, string name) { if( Parties[name] ) return "A party by that name already exists."; if( member_array(name, (string *)CHAT_D->GetChannels()) != -1 ) ! return "You cannot use the name " + name + " for your party."; if( (string)who->GetParty() ) return "You are already in a party!"; return 1; } *************** *** 45,65 **** pname = (string)who->GetParty(); if( !Parties[pname] ) return "There is no such party!"; if( ((class party)Parties[pname])->Leader != who ) ! return "Only the party leader may add members!"; if( (string)member->GetParty() ) ! return (string)member->GetName() + " is already in a party."; if( environment(member) != environment(who) ) ! return (string)member->GetName() + " must be somewhere near you."; return 1; } mixed CanJoinParty(object who, string pname) { if( !Parties[pname] ) return "There is no such party."; if( member_array(who, ((class party)Parties[pname])->Invited) == -1 ) ! return "You have not been invited to join that party."; if( (string)who->GetParty() ) return "You are already in a party."; if( environment(who) != environment(((class party)Parties[pname])->Leader) ) ! return "You are nowhere the leader of the party."; return 1; } --- 45,65 ---- pname = (string)who->GetParty(); if( !Parties[pname] ) return "There is no such party!"; if( ((class party)Parties[pname])->Leader != who ) ! return "Only the party leader may add members!"; if( (string)member->GetParty() ) ! return (string)member->GetName() + " is already in a party."; if( environment(member) != environment(who) ) ! return (string)member->GetName() + " must be somewhere near you."; return 1; } mixed CanJoinParty(object who, string pname) { if( !Parties[pname] ) return "There is no such party."; if( member_array(who, ((class party)Parties[pname])->Invited) == -1 ) ! return "You have not been invited to join that party."; if( (string)who->GetParty() ) return "You are already in a party."; if( environment(who) != environment(((class party)Parties[pname])->Leader) ) ! return "You are nowhere the leader of the party."; return 1; } *************** *** 70,76 **** pname = (string)who->GetParty(); if( !pname || !(p = Parties[pname]) ) return "There is no such party."; if( member_array(who, p->Members) == -1 ) ! return "You are not in that party."; return 1; } --- 70,76 ---- pname = (string)who->GetParty(); if( !pname || !(p = Parties[pname]) ) return "There is no such party."; if( member_array(who, p->Members) == -1 ) ! return "You are not in that party."; return 1; } *************** *** 81,87 **** pname = (string)who->GetParty(); if( !(p = Parties[pname]) ) return "There is no such party."; if( p->Leader != who ) return "Only the party leader may remove people."; ! return 1; } mixed CanRemoveParty(object who) { --- 81,87 ---- pname = (string)who->GetParty(); if( !(p = Parties[pname]) ) return "There is no such party."; if( p->Leader != who ) return "Only the party leader may remove people."; ! return 1; } mixed CanRemoveParty(object who) { *************** *** 91,97 **** pname = (string)who->GetParty(); if( !(p = Parties[pname]) ) return "There is no such party!"; if( p->Leader != who ) ! return "Only the party leader may disband the party."; return 1; } --- 91,97 ---- pname = (string)who->GetParty(); if( !(p = Parties[pname]) ) return "There is no such party!"; if( p->Leader != who ) ! return "Only the party leader may disband the party."; return 1; } *************** *** 103,109 **** p = Parties[pname]; p->Leader = targ; CHAT_D->eventSend("System", pname, (string)targ->GetName() + " is now " ! "the leader."); return 1; } --- 103,109 ---- p = Parties[pname]; p->Leader = targ; CHAT_D->eventSend("System", pname, (string)targ->GetName() + " is now " ! "the leader."); return 1; } *************** *** 111,117 **** class party this_party; if( (string)who->SetParty(name) != name ) ! return "There was some bizarre problem sticking you in a party."; this_party = new(class party); this_party->Leader = who; this_party->Members = ({ who }); --- 111,117 ---- class party this_party; if( (string)who->SetParty(name) != name ) ! return "There was some bizarre problem sticking you in a party."; this_party = new(class party); this_party->Leader = who; this_party->Members = ({ who }); *************** *** 123,155 **** mixed eventInviteMember(object who, object targ) { class party this_party; - mixed tmp; string name; name = (string)who->GetParty(); this_party = Parties[name]; this_party->Invited += ({ targ }); CHAT_D->eventSendChannel("System", name, (string)targ->GetName() + ! " has been invited to join the party."); call_out((: RemoveInvitiation :), 60, name, targ); targ->eventPrint("You have been invited to join the party \"" + name + ! "\".\nType \"party join " + name + "\" in 60 " ! "seconds to join.", MSG_SYSTEM); return 1; } mixed eventJoinParty(object who, string name) { class party this_party; mixed tmp; ! if( (tmp = CanJoinParty(who, name)) != 1 ) return tmp; this_party = Parties[name]; if( (string)who->SetParty(name) != name ) ! return "Bogus error in joining party."; this_party->Invited -= ({ who }); this_party->Members += ({ who }); CHAT_D->eventSendChannel("System", name, (string)who->GetName() + ! " has joined the party."); return 1; } --- 123,154 ---- mixed eventInviteMember(object who, object targ) { class party this_party; string name; name = (string)who->GetParty(); this_party = Parties[name]; this_party->Invited += ({ targ }); CHAT_D->eventSendChannel("System", name, (string)targ->GetName() + ! " has been invited to join the party."); call_out((: RemoveInvitiation :), 60, name, targ); targ->eventPrint("You have been invited to join the party \"" + name + ! "\".\nType \"party join " + name + "\" in 60 " ! "seconds to join.", MSG_SYSTEM); return 1; } mixed eventJoinParty(object who, string name) { class party this_party; mixed tmp; ! if( (tmp = CanJoinParty(who, name)) != 1 ) return tmp; this_party = Parties[name]; if( (string)who->SetParty(name) != name ) ! return "Bogus error in joining party."; this_party->Invited -= ({ who }); this_party->Members += ({ who }); CHAT_D->eventSendChannel("System", name, (string)who->GetName() + ! " has joined the party."); return 1; } *************** *** 171,177 **** else { p->Leader = ob; ob->eventPrint("You are now the leader of the party " + name + ! ".", MSG_SYSTEM); } } } --- 170,176 ---- else { p->Leader = ob; ob->eventPrint("You are now the leader of the party " + name + ! ".", MSG_SYSTEM); } } } *************** *** 179,188 **** if( Parties[name] ) { p->Members -= ({ targ }); CHAT_D->eventSendChannel("System", name, (string)targ->GetName() + ! " is no longer in the party."); } targ->eventPrint("You are no longer a member of the party " + name + ! ".", MSG_SYSTEM); return 1; } --- 178,187 ---- if( Parties[name] ) { p->Members -= ({ targ }); CHAT_D->eventSendChannel("System", name, (string)targ->GetName() + ! " is no longer in the party."); } targ->eventPrint("You are no longer a member of the party " + name + ! ".", MSG_SYSTEM); return 1; } *************** *** 192,200 **** name = (string)who->GetParty(); CHAT_D->eventSendChannel("System", name, "The party " + name + " has been " ! "disbanded."); foreach(ob in ((class party)Parties[name])->Members) ! ob->SetParty(0); map_delete(Parties, name); return 1; } --- 191,199 ---- name = (string)who->GetParty(); CHAT_D->eventSendChannel("System", name, "The party " + name + " has been " ! "disbanded."); foreach(ob in ((class party)Parties[name])->Members) ! ob->SetParty(0); map_delete(Parties, name); return 1; } *************** *** 202,208 **** object GetPartyLeader(string name) { class party p; string nom; ! foreach(nom, p in Parties) if( nom == name ) return p->Leader; return 0; } --- 201,207 ---- object GetPartyLeader(string name) { class party p; string nom; ! foreach(nom, p in Parties) if( nom == name ) return p->Leader; return 0; } *************** *** 218,223 **** static void RemoveInvitiation(string name, object who) { if( !Parties[name] ) return; if( member_array(who, ((class party)Parties[name])->Invited) == -1 ) ! return; ((class party)Parties[name])->Invited -= ({ who }); } --- 217,222 ---- static void RemoveInvitiation(string name, object who) { if( !Parties[name] ) return; if( member_array(who, ((class party)Parties[name])->Invited) == -1 ) ! return; ((class party)Parties[name])->Invited -= ({ who }); } diff -c -r --new-file ds1.1/lib/daemon/preload_check.c ds2.1/lib/daemon/preload_check.c *** ds1.1/lib/daemon/preload_check.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/daemon/preload_check.c Wed Jul 5 00:00:58 2006 *************** *** 0 **** --- 1,24 ---- + #include <lib.h> + #include <daemons.h> + #include <cfg.h> + + inherit LIB_DAEMON; + + string *preloads; + + static void checkPreloads(){ + foreach(string daemon in preloads){ + if(!find_object(daemon) && daemon != INTERMUD_D && + daemon != AUTOEXEC_D) + update(daemon); + } + call_out((: checkPreloads :), 300); + } + + static void create() { + daemon::create(); + SetNoClean(1); + preloads = filter(explode(read_file(CFG_PRELOAD),"\n"), (: !grepp($1,"#") :) ); + call_out((: checkPreloads :), 300); + } + diff -c -r --new-file ds1.1/lib/daemon/races.c ds2.1/lib/daemon/races.c *** ds1.1/lib/daemon/races.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/races.c Tue Jul 11 18:30:59 2006 *************** *** 3,63 **** * handles race configuration and administration * created by Descartes of Borg 960108 * Version: @(#) races.c 1.4@(#) ! * Last modified: 96/11/10 */ #include <lib.h> #include <save.h> #include <privs.h> #include "include/races.h" inherit LIB_DAEMON; private mapping Races = ([]); static private mapping Resistances = ([]); ! static private mapping Armours = ([]); static void create() { string array lines; ! daemon::create(); if( unguarded((: file_size(SAVE_RACES __SAVE_EXTENSION__) :)) > 0 ) unguarded((: restore_object(SAVE_RACES) :)); if( !Races ) Races = ([]); ! // Hocus pocus to load armour and resistance info ! lines = explode(read_file("/include/armour_types.h"), "\n"); foreach(string line in lines) { string type; if( sscanf(line, "#define %s %*s", type) == 2 ) { string file = DIR_DAEMONS "/tmp/" + type + ".c"; ! if( type == "A_MAX_ARMOUR_BIT" ) { continue; } if( !file_exists(file) ) { ! unguarded((: write_file($(file), "#include <armour_types.h>\n" ! "int armour() { return " + ! $(type) + "; }\n") :)); } ! Armours[type] = call_other(file, "armour"); } } lines = explode(read_file("/include/damage_types.h"), "\n"); foreach(string line in lines) { string type; if( sscanf(line, "#define %s %*s", type) == 2 ) { string file = DIR_DAEMONS "/tmp/" + type + ".c"; - if( type == "MAX_DAMAGE_BIT" ) { continue; } if( !file_exists(file) ) { unguarded((: write_file($(file), "#include <damage_types.h>\n" ! "int damage() { return " + ! $(type) + "; }\n") :)); } Resistances[type] = call_other(file, "damage"); } } --- 3,83 ---- * handles race configuration and administration * created by Descartes of Borg 960108 * Version: @(#) races.c 1.4@(#) ! * Fixed by Ashon @ Stargate Atlantis 16 March 2006 */ #include <lib.h> #include <save.h> #include <privs.h> + #include <armor_types.h> #include "include/races.h" inherit LIB_DAEMON; private mapping Races = ([]); static private mapping Resistances = ([]); ! static private mapping Armors = ([]); ! string array FlyingRaces = ({"wtf"}); ! string array LimblessCombatRaces = ({}); ! string array LimblessRaces = ({}); ! string array NonBitingRaces = ({}); ! ! ! string wtf = "/tmp/wtf.txt"; ! static void create() { string array lines; ! daemon::create(); + if( unguarded((: file_size(SAVE_RACES __SAVE_EXTENSION__) :)) > 0 ) unguarded((: restore_object(SAVE_RACES) :)); + if( !Races ) Races = ([]); ! if(!FlyingRaces) FlyingRaces = ({}); ! if(!LimblessCombatRaces) LimblessCombatRaces = ({}); ! if(!LimblessRaces) LimblessRaces = ({}); ! if(!NonBitingRaces) NonBitingRaces = ({}); ! ! // Hocus pocus to load armor and resistance info ! lines = explode(read_file("/include/armor_types.h"), "\n"); foreach(string line in lines) { string type; if( sscanf(line, "#define %s %*s", type) == 2 ) { string file = DIR_DAEMONS "/tmp/" + type + ".c"; ! if( type == "A_MAX_ARMOR_BIT" ) { continue; } + if( !file_exists(file) ) { ! unguarded((: write_file($(file), "#include <armor_types.h>\n" ! "int armor() { return " + ! $(type) + "; }\n") :)); } ! ! Armors[type] = call_other(file, "armor"); } } + lines = explode(read_file("/include/damage_types.h"), "\n"); foreach(string line in lines) { string type; if( sscanf(line, "#define %s %*s", type) == 2 ) { string file = DIR_DAEMONS "/tmp/" + type + ".c"; if( type == "MAX_DAMAGE_BIT" ) { continue; } + if( !file_exists(file) ) { unguarded((: write_file($(file), "#include <damage_types.h>\n" ! "int damage() { return " + ! $(type) + "; }\n") :)); } + Resistances[type] = call_other(file, "damage"); } } *************** *** 68,313 **** error("Illegal attempt to modify race data"); } ! void AddRace(string file, int player) { ! class Race res; ! string array lines, tmp; ! string race; ! ! validate(); ! if( !file_exists(file) ) error("No such file: " + file); ! lines = explode(read_file(file), "\n"); ! lines = filter(lines, function(string str) { ! if( strlen(str) == 0 ) { ! return 0; ! } ! if( str[0] == '#' ) { ! return 0; ! } ! if( str[0] == ' ' || str[0] == '\t' ) { ! return 0; ! } ! return 1; ! }); ! race = lines[0]; ! if( Races[race] ) error("Race already exists"); ! res = new(class Race); ! res->Sensitivity = map(explode(lines[1], ":"), (: to_int :)); ! res->Language = lines[2]; ! lines = lines[3..]; ! res->Resistance = ([]); ! while(sizeof(tmp = explode(lines[0], ":")) == 2) { ! int x = to_int(tmp[0]); ! ! if( x == 0 && tmp[0] != "0" ) x = GetResistance(tmp[0]); ! res->Resistance[x] = tmp[1]; ! lines = lines[1..]; ! } ! res->Stats = ([]); ! while(sizeof(tmp = explode(lines[0], ":")) == 3) { ! class Stat s = new (class Stat); ! s->Average = to_int(tmp[1]); ! s->Class = to_int(tmp[2]); ! res->Stats[tmp[0]] = s; ! lines = lines[1..]; ! } ! res->Limbs = ({}); ! while(sizeof(tmp = explode(lines[0], ":")) == 4) { ! mixed array limb = allocate(4); ! limb[0] = tmp[0]; ! limb[1] = (tmp[1] == "0" ? 0 : tmp[1]); ! limb[2] = to_int(tmp[2]); ! limb[3] = map(explode(tmp[3], ","), function(string str) { ! int x = to_int(str); ! ! if( x == 0 && str != "0" ) ! return GetArmour(str); ! return x; ! }); ! res->Limbs = ({ res->Limbs..., limb }); ! if( sizeof(lines) > 1 ) lines = lines[1..]; ! else { ! lines = ({}); ! break; ! } ! } ! res->Fingers = ([]); ! if( sizeof(lines) ) { ! foreach(string hand in lines) { ! string array parts = explode(hand, ":"); ! res->Fingers[parts[0]] = to_int(parts[1]); ! } ! } ! res->Complete = 1; ! if( player ) { ! res->PlayerFlag = 1; ! } ! else { ! res->PlayerFlag = 0; ! } ! Races[race] = res; ! save_object(SAVE_RACES); } ! void RemoveRace(string race) { ! validate(); ! map_delete(Races, race); ! save_object(SAVE_RACES); } ! int GetArmour(string str) { ! string file = DIR_DAEMONS "/tmp/" + str + ".c"; ! ! if( !unguarded((: file_exists($(file)) :)) ) { ! unguarded((: write_file($(file), "#include <armour_types.h>\n" + ! "int armour() { return " + $(str) + "; }\n") :)); ! } ! return call_other(file, "armour"); } ! int GetResistance(string str) { ! string file = DIR_DAEMONS "/tmp/" + str + ".c"; ! ! if( !unguarded((: file_exists($(file)) :)) ) { ! unguarded((: write_file($(file), "#include <damage_types.h>\n" + ! "int damage() { return " + $(str) + "; }\n") :)); ! } ! return call_other(file, "damage"); } ! mapping GetRemoteRaces() { ! mapping mp = ([]); ! foreach(string race, class Race res in Races) { ! mapping stats = ([]); ! mp[race] = ([]); ! mp[race]["limbs"] = res->Limbs; ! mp[race]["resistance"] = res->Resistance; ! foreach(string stat, class Stat st in res->Stats) { ! stats[stat] = ([]); ! stats[stat]["class"] = st->Class; ! stats[stat]["average"] = st->Average; ! } ! mp[race]["stats"] = stats; ! mp[race]["fingers"] = res->Fingers; ! mp[race]["sensitivity"] = res->Sensitivity; ! mp[race]["player"] = res->PlayerFlag; ! mp[race]["language"] = res->Language; ! } ! return mp; } ! void SetComplete(string race) { ! class Race res; ! ! validate(); ! if( !Races[race] ) error("No such race"); ! else res = Races[race]; ! res->Complete = 1; ! save_object(SAVE_RACES); } ! void SetLightSensitivity(string race, int array sensitivity) { class Race res; ! validate(); - if( !Races[race] ) error("No such race"); - else res = Races[race]; - if( sensitivity[0] < 1 ) error("Invalid sensitivity value"); - if( sensitivity[1] > 99 ) error("Invalid sensitivity value"); - if( sensitivity[0] > sensitivity[1] ) error("Invalid sensitivity value"); - res->Sensitivity = sensitivity; - save_object(SAVE_RACES); - } - - void SetCharacterLimbs(string race, mixed array args) { - class Race res = Races[race]; - mixed array tmp = ({}); - - if( !res || !res->Complete || sizeof(args) != 2 ) return; - args[0] = copy(res->Limbs); - foreach(string finger, int count in res->Fingers) - tmp = ({ tmp..., ({ finger, count }) }); - args[1] = tmp; - } - - void SetCharacterRace(string race, mixed array args) { - class Race res = Races[race]; - mixed array tmp; - - if( !res || !res->Complete || sizeof(args) != 4 ) return; - tmp = ({}); - foreach(int key, string val in res->Resistance) - tmp = ({ tmp..., ({ key, val }) }); - args[0] = tmp; - tmp = ({}); - foreach(string key, class Stat stat in res->Stats) - tmp = ({ tmp..., ({ key, stat->Average, stat->Class }) }); - args[1] = tmp; - args[2] = res->Language; - args[3] = ({ res->Sensitivity[0], res->Sensitivity[1] }); - } - - varargs string array GetRaces(int player_only) { - return filter(keys(Races), function(string race, int player_only) { - class Race res = Races[race]; - - if( !res->Complete ) return 0; - if( player_only && !res->PlayerFlag ) - return 0; - return 1; - }, player_only); - } - - string GetHelp(string race) { - class Race res = Races[race]; - string array limbs; - string help = "Race: " + race + "\n\n"; - string tmp; - int x; - - if( !res ) return 0; - limbs = map(res->Limbs, (: $1[0] :)); - help += "Limbs:\n"; - help += capitalize(item_list(map(limbs, (: add_article :)))) + ".\n"; - help += "\nFingered limbs:\n"; - foreach(string finger, int count in res->Fingers) - help += "\t" + finger + " (" + count + ")\n"; - limbs = regexp(limbs, ".* wing"); - if( sizeof(limbs) ) { - help += "\nFlying\n"; - } - else { - help += "\nNon-flying\n"; - } - x = res->Sensitivity[0]; - if( x < 11 ) tmp = "excellent"; - else if( x < 16 ) tmp = "above average"; - else if( x < 21 ) tmp = "good"; - else if( x < 26 ) tmp = "average"; - else if( x < 31 ) tmp = "below average"; - else if( x < 36 ) tmp = "very poor"; - else tmp = "extremely poor"; - help += "\nNight vision: " + tmp + "\n"; - x = res->Sensitivity[1]; - if( x < 61 ) tmp = "extremely poor"; - else if( x < 66 ) tmp = "very poor"; - else if( x < 71 ) tmp = "below average"; - else if( x < 76 ) tmp = "average"; - else if( x < 81 ) tmp = "good"; - else if( x < 86 ) tmp = "above average"; - else tmp = "excellent"; - help += "Day vision: " + tmp + "\n\n"; - return help; - } ! public mapping GetResistances() { ! return copy(Resistances); ! } - public mapping GetArmours() { - return copy(Armours); - } --- 88,479 ---- error("Illegal attempt to modify race data"); } ! int CanFly(string str){ ! if( !Races[str] ) return 0; ! if(member_array(str, FlyingRaces) != -1) return 1; ! else return 0; ! } ! int GetLimblessCombatRace(string str){ ! if(member_array(str,LimblessCombatRaces) == -1) return 0; ! else return 1; ! } ! int GetLimblessRace(string str){ ! if(member_array(str,LimblessRaces) == -1) return 0; ! else return 1; ! } ! int SetLimblessCombatRace(string str){ ! if(member_array(str,LimblessCombatRaces) != -1) return 0; ! LimblessCombatRaces += ({ lower_case(str) }); ! return 1; } ! int SetLimblessRace(string str){ ! if(member_array(str,LimblessRaces) != -1) return 0; ! LimblessRaces += ({ lower_case(str) }); ! return 1; } ! int SetFlyingRace(string str){ ! //if(member_array(str,FlyingRaces) != -1) return 0; ! FlyingRaces += ({ str }); ! return 1; } ! int SetNonBitingRace(string str){ ! //if(member_array(str,FlyingRaces) != -1) return 0; ! NonBitingRaces += ({ str }); ! return 1; } ! string *GetLimblessCombatRaces(){ ! return LimblessCombatRaces; ! } ! string *GetLimblessRaces(){ ! return LimblessRaces; ! } ! string *GetFlyingRaces(){ ! return FlyingRaces; } ! int GetBitingRace(string str){ ! if(member_array(str,NonBitingRaces) == -1) return 1; ! else return 0; } ! void AddRace(string file, int player) { class Race res; ! string array lines, tmp, parts; ! string race, test_string; ! int i, x; ! mixed array limb = allocate(4); ! mixed array tmp_limb = allocate(4); ! class Stat s; ! ! res = new(class Race); ! ! res->Resistance = ([]); ! res->Skills = ([]); ! res->Stats = ([]); ! res->Limbs = ({}); ! validate(); ! if( !file_exists(file) ) error("No such file: " + file); ! race = last_string_element(file,"/"); ! ! lines = explode(read_file(file), "\n"); ! ! lines = filter(lines, function(string str) { ! if( strlen(str) == 0 ) { ! return 0; ! } ! if( str[0] == '#' ) { ! return 0; ! } ! if( str[0] == ' ' || str[0] == '\t' ) { ! return 0; ! } ! return 1; ! }); ! ! res->Fingers = ([]); ! ! ! foreach(string line in explode(read_file(file),"\n")){ ! test_string = first_string_element(line," "); ! if(!test_string || !sizeof(test_string)) test_string = line; ! ! switch(test_string){ ! ! case "FLYINGRACE": ! SetFlyingRace(race); ! break; ! ! case "LIMBLESSRACE": ! SetLimblessRace(race); ! break; ! ! case "LIMBLESSCOMBATRACE": ! SetLimblessCombatRace(race); ! break; ! ! case "NONBITINGRACE": ! SetNonBitingRace(race); ! break; ! ! case "RACE": ! race = replace_string(line, "RACE ", ""); ! if( Races[race] ) error(race+": Race already exists"); ! break; ! ! case "SENSITIVITY": ! line = replace_string(line, "SENSITIVITY ", ""); ! res->Sensitivity = map(explode(line, ":"), (: to_int :)); ! break; ! ! case "PLAYER_RACE": ! line = replace_string(line, "PLAYER_RACE ", ""); ! if(!player && to_int(line) > 0) player = 1; ! break; ! ! case "LANGUAGE": ! //TODO: This should be a Language array to handle multiple ! //languages but further research is required first. ! res->Language = replace_string(line, "LANGUAGE ", ""); ! break; ! ! case "RESISTANCE": ! tmp = explode(replace_string(line, "RESISTANCE ", ""), ":"); ! x = to_int(tmp[0]); ! if( x == 0 && tmp[0] != "0" ) x = GetResistance(tmp[0]); ! res->Resistance[x] = tmp[1]; ! break; ! ! case "SKILL": ! tmp = explode(replace_string(line, "SKILL ", ""), ":"); ! res->Skills[tmp[0]] = ({ tmp[1], tmp[2], tmp[3], tmp[4] }); ! break; ! ! case "STATS": ! tmp = ({}); ! s = new (class Stat); ! tmp = explode(replace_string(line, "STATS ",""), ":"); ! s->Average = copy(to_int(tmp[1])); ! s->Class = copy(to_int(tmp[2])); ! res->Stats[tmp[0]] = s; ! break; ! ! case "LIMB": ! limb = ({ ({}), ({}), ({}), ({}) }); ! tmp_limb = explode(replace_string(line, "LIMB ",""), ":"); ! limb[0] = tmp_limb[0]; ! limb[1] = (tmp_limb[1] == "0" ? 0 : tmp_limb[1]); ! limb[2] = to_int(tmp_limb[2]); ! limb[3] = map(explode(tmp_limb[3], ","), function(string str) { ! int x = to_int(str); ! if( x == 0 && str != "0" ) { return GetArmor(str); } ! return x; ! }); ! ! res->Limbs = ({ res->Limbs..., limb }); ! res->Limbs += ({limb}); ! break; ! ! case "HAND": ! parts = explode(replace_string(line, "HAND ",""), ":"); ! res->Fingers[parts[0]] = to_int(parts[1]); ! break; ! ! default: ! break; ! } ! } ! ! res->Complete = 1; ! ! if( player ) { ! res->PlayerFlag = 1; ! } ! ! else { ! res->PlayerFlag = 0; ! } ! ! Races[race] = res; ! wtf = save_variable(Races[race]); ! save_object(SAVE_RACES); ! } ! ! void RemoveRace(string race) { ! validate(); ! wtf = save_variable(Races[race]); ! map_delete(Races, race); ! if(Races[race]) ! save_object(SAVE_RACES); ! } ! ! ! int GetArmor(string str) { ! string file = DIR_DAEMONS "/tmp/" + str + ".c"; ! ! if( !unguarded((: file_exists($(file)) :)) ) { ! unguarded((: write_file($(file), "#include <armor_types.h>\n" + ! "int armor() { return " + $(str) + "; }\n") :)); ! } ! return call_other(file, "armor"); ! } ! ! int GetResistance(string str) { ! string file = DIR_DAEMONS "/tmp/" + str + ".c"; ! ! if( !unguarded((: file_exists($(file)) :)) ) { ! unguarded((: write_file($(file), "#include <damage_types.h>\n" + ! "int damage() { return " + $(str) + "; }\n") :)); ! } ! return call_other(file, "damage"); ! } ! ! varargs mapping GetRemoteRaces(string str) { ! mapping mp = ([]); ! mapping foo = ([]); ! ! if(str && Races[str]) foo[str] = Races[str]; ! else foo = copy(Races); ! ! foreach(string race, class Race res in foo) { ! mapping stats = ([]); ! ! mp[race] = ([]); ! mp[race]["limbs"] = res->Limbs; ! mp[race]["resistance"] = res->Resistance; ! ! foreach(string stat, class Stat st in res->Stats) { ! stats[stat] = ([]); ! stats[stat]["class"] = st->Class; ! stats[stat]["average"] = st->Average; ! } ! ! mp[race]["stats"] = stats; ! mp[race]["fingers"] = res->Fingers; ! mp[race]["sensitivity"] = res->Sensitivity; ! mp[race]["player"] = res->PlayerFlag; ! mp[race]["language"] = res->Language; ! ! } ! return mp; ! } ! ! void SetComplete(string race) { ! class Race res; ! ! validate(); ! ! if( !Races[race] ) error("No such race"); ! else res = Races[race]; ! res->Complete = 1; ! save_object(SAVE_RACES); ! } ! ! void SetLightSensitivity(string race, int array sensitivity) { ! class Race res; ! ! validate(); ! ! if( !Races[race] ) error("No such race"); ! else res = Races[race]; ! if( sensitivity[0] < 1 ) error("Invalid sensitivity value"); ! if( sensitivity[1] > 99 ) error("Invalid sensitivity value"); ! if( sensitivity[0] > sensitivity[1] ) error("Invalid sensitivity value"); ! res->Sensitivity = sensitivity; ! save_object(SAVE_RACES); ! } ! ! void SetCharacterLimbs(string race, mixed array args) { ! class Race res = Races[race]; ! mixed array tmp = ({}); ! ! if( !res || !res->Complete || sizeof(args) != 2 ) return; ! args[0] = copy(res->Limbs); ! foreach(string finger, int count in res->Fingers) ! tmp = ({ tmp..., ({ finger, count }) }); ! args[1] = tmp; ! } ! ! void SetCharacterRace(string race, mixed array args) { ! class Race res = Races[race]; ! mixed array tmp; ! mapping StatMap; ! string schluss; ! ! if( !res || !res->Complete || sizeof(args) != 5 ) return; ! tmp = ({}); ! foreach(int key, string val in res->Resistance) ! tmp = ({ tmp..., ({ key, val }) }); ! args[0] = tmp; ! tmp = ({}); ! StatMap = copy(res->Stats); ! schluss = ""; ! foreach(schluss in keys(StatMap)){ ! tmp = ({ tmp..., ({ schluss, StatMap[schluss]->Average, StatMap[schluss]->Class }) }); ! } ! args[1] = tmp; ! args[2] = res->Language; ! args[3] = res->Sensitivity; ! args[4] = res->Skills; ! } ! ! varargs string array GetRaces(int player_only) { ! ! return filter(keys(Races), function(string race, int player_only) { ! class Race res = Races[race]; ! ! if( !res->Complete ) return 0; ! if( player_only && !res->PlayerFlag ) ! return 0; ! return 1; ! }, player_only); ! } ! ! string GetHelp(string race) { ! class Race res = Races[race]; ! string array limbs; ! string help = "Race: " + race + "\n\n"; ! string tmp, h_file; ! int x; ! ! if( !res ) return 0; ! h_file = "/doc/help/races/"+lower_case(race); ! if(file_exists(h_file)) return read_file(h_file); ! limbs = map(res->Limbs, (: $1[0] :)); ! limbs = singular_array(limbs); ! help += "Limbs:\n"; ! help += capitalize(item_list(map(limbs, (: add_article :)))) + ".\n"; ! help += "\nFingered limbs:\n"; ! foreach(string finger, int count in res->Fingers) ! help += "\t" + finger + " (" + count + ")\n"; ! limbs = regexp(limbs, ".* wing"); ! if( sizeof(limbs) ) { ! help += "\nFlying\n"; ! } ! ! else { ! help += "\nNon-flying\n"; ! } ! ! x = res->Sensitivity[0]; ! if( x < 11 ) tmp = "excellent"; ! else if( x < 16 ) tmp = "above average"; ! else if( x < 21 ) tmp = "good"; ! else if( x < 26 ) tmp = "average"; ! else if( x < 31 ) tmp = "below average"; ! else if( x < 36 ) tmp = "very poor"; ! else tmp = "extremely poor"; ! help += "\nNight vision: " + tmp + "\n"; ! x = res->Sensitivity[1]; ! if( x < 61 ) tmp = "extremely poor"; ! else if( x < 66 ) tmp = "very poor"; ! else if( x < 71 ) tmp = "below average"; ! else if( x < 76 ) tmp = "average"; ! else if( x < 81 ) tmp = "good"; ! else if( x < 86 ) tmp = "above average"; ! else tmp = "excellent"; ! help += "Day vision: " + tmp + "\n\n"; ! return help; ! } ! ! public mapping GetResistances() { ! return copy(Resistances); ! } ! ! ! ! public mapping GetArmors() { ! return copy(Armors); ! } ! diff -c -r --new-file ds1.1/lib/daemon/reaper.c ds2.1/lib/daemon/reaper.c *** ds1.1/lib/daemon/reaper.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/daemon/reaper.c Wed Jul 5 00:00:58 2006 *************** *** 0 **** --- 1,23 ---- + /* + * Seeks dummy items without an environment and destroys them. + * Hackey workaround to sloppy code I'm still tracking down. + * -Crat 21Jan06 + */ + + #include <lib.h> + + inherit LIB_DAEMON; + + static void eventReap() { + + call_out((: eventReap :), 300); + + reap_dummies(); + } + + static void create() { + daemon::create(); + SetNoClean(1); + call_out((: eventReap :), 300); + } + diff -c -r --new-file ds1.1/lib/daemon/seasons.c ds2.1/lib/daemon/seasons.c *** ds1.1/lib/daemon/seasons.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/seasons.c Wed Jul 5 00:00:58 2006 *************** *** 14,19 **** --- 14,20 ---- inherit LIB_DAEMON; private static int CurrentDay, CurrentYear, Dawn, Morning, Twilight, Night; + private static int ticktock; private static string CurrentSeason, TimeOfDay; private static mapping Moons; private static class month CurrentMonth; *************** *** 22,27 **** --- 23,42 ---- private static function *NightCalls, *MidnightCalls; private static class month *Months; + int eventTickTock(int tick){ + if(!tick) tick = 0; + ticktock = tick; + eventConfigure(); + return GetCurrentTime()/1200; + } + + int GetTickTock(){ return ticktock; } + + int *GetMudTime(){ + return ({ GetHour(GetCurrentTime()), GetMinutes(GetCurrentTime()) }); + } + + static void create() { string *lines; int i, maxi; *************** *** 32,63 **** TwilightCalls = ({}); NightCalls = ({}); MidnightCalls = ({}); 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(); } --- 47,79 ---- 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(); } *************** *** 67,115 **** 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); } } --- 83,131 ---- 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 + 4) * HOUR_LENGTH) - x) / 3) * 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); } } *************** *** 120,129 **** 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])); } --- 136,145 ---- 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])); } *************** *** 135,144 **** 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])); } --- 151,160 ---- 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])); } *************** *** 150,159 **** 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])); } --- 166,175 ---- 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])); } *************** *** 165,172 **** call_out( (: eventMidnight :), DAY_LENGTH - GetCurrentTime() ); 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])); --- 181,188 ---- call_out( (: eventMidnight :), DAY_LENGTH - GetCurrentTime() ); 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])); *************** *** 178,191 **** 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"; --- 194,207 ---- 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"; *************** *** 201,207 **** string GetCurrentSeason() { return CurrentSeason; } ! int GetCurrentTime() { return (time()- DAY_ONE) % (DAY_LENGTH * HOUR_LENGTH); } int GetCurrentYear() { return CurrentYear; } --- 217,223 ---- string GetCurrentSeason() { return CurrentSeason; } ! int GetCurrentTime() { return (time()- DAY_ONE) % (DAY_LENGTH * HOUR_LENGTH) + ticktock; } int GetCurrentYear() { return CurrentYear; } *************** *** 210,229 **** 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; } --- 226,245 ---- 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; } *************** *** 242,249 **** i = sizeof(Months); while(i--) { ! if( ((class month)Months[i])->Name == mon ) ! return ((class month)Months[i])->DaylightHours; } return 0; } --- 258,265 ---- i = sizeof(Months); while(i--) { ! if( ((class month)Months[i])->Name == mon ) ! return ((class month)Months[i])->DaylightHours; } return 0; } *************** *** 268,274 **** string GetMonth(int x) { int monthIndex; ! monthIndex = GetMonthIndex(x); return Months[monthIndex]->Name; } --- 284,290 ---- string GetMonth(int x) { int monthIndex; ! monthIndex = GetMonthIndex(x); return Months[monthIndex]->Name; } *************** *** 279,299 **** 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; } --- 295,315 ---- 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; } *************** *** 303,315 **** 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; } --- 319,331 ---- 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; } *************** *** 320,339 **** 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) { --- 336,355 ---- 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) { *************** *** 356,366 **** val = GetPhase(val); } switch(val) { ! case 0: return "new"; ! case 1: return "waxing"; ! case 2: return "waning"; ! case 3: return "full"; ! default: return "error"; } } --- 372,382 ---- val = GetPhase(val); } switch(val) { ! case 0: return "new"; ! case 1: return "waxing"; ! case 2: return "waning"; ! case 3: return "full"; ! default: return "error"; } } *************** *** 388,398 **** i = sizeof(moons = keys(Moons)); while(i--) { ! int z; ! z = GetPhase(moons[i]); ! if( z == 4) z = 2; ! y += z; } return y; } --- 404,414 ---- i = sizeof(moons = keys(Moons)); while(i--) { ! int z; ! z = GetPhase(moons[i]); ! if( z == 4) z = 2; ! y += z; } return y; } *************** *** 404,474 **** int i; 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 "There is no sun to be seen."; ! } ! case "moon": case "moons": ! if( GetTimeOfDay() != "night" ) return "During the day?"; ! else { ! string *moons; ! int x = 0; ! ! i = sizeof(moons = keys(Moons)); ! while(i--) { ! int y; ! ! if( y = GetPhase(moons[i]) ) continue; ! else if( 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) + ". "; ! x = 1; ! } ! if( !x ) return 0; ! 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; ! } ! } ! 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); --- 420,490 ---- int i; 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 "There is no sun to be seen."; ! } ! case "moon": case "moons": ! if( GetTimeOfDay() != "night" ) return "During the day?"; ! else { ! string *moons; ! int x = 0; ! ! i = sizeof(moons = keys(Moons)); ! while(i--) { ! int y; ! ! if( y = GetPhase(moons[i]) ) continue; ! else if( 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) + ". "; ! x = 1; ! } ! if( !x ) return 0; ! 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; ! } ! } ! 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); *************** *** 497,527 **** tmp = sky + "\n" + tmp; } } ! } ! return tmp; ! } ! default: ! if( Moons[arg] ) return ((class moon)Moons[arg])->Description; ! arr = map(mn = keys(Moons), (: ((class moon)Moons[$1])->Id :)); ! if( (i = member_array(arg, arr)) != -1 ) ! return ((class moon)Moons[mn[i]])->Description; ! 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 indoors!"); - return 1; - } - who->eventPrint(str); - environment(who)->eventPrint((string)who->GetName() + " gazes toward the sky.", who); - return 1; - } --- 513,543 ---- tmp = sky + "\n" + tmp; } } ! } ! return tmp; ! } ! default: ! if( Moons[arg] ) return ((class moon)Moons[arg])->Description; ! arr = map(mn = keys(Moons), (: ((class moon)Moons[$1])->Id :)); ! if( (i = member_array(arg, arr)) != -1 ) ! return ((class moon)Moons[mn[i]])->Description; ! 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 indoors!"); ! return 1; ! } ! who->eventPrint(str); ! environment(who)->eventPrint((string)who->GetName() + " gazes toward the sky.", who); ! return 1; } diff -c -r --new-file ds1.1/lib/daemon/services/auth.c ds2.1/lib/daemon/services/auth.c *** ds1.1/lib/daemon/services/auth.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/daemon/services/auth.c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,44 ---- + #define SERVICE_AUTH + + #include <daemons.h> + #include <rooms.h> + #include <message_class.h> + + void eventReceiveAuthReply(mixed array packet) { + object pinger; + object *pingers = filter( users(), (: $1->GetProperty("pinging") :) ); + PING_D->SetOK(); + if(pinger = find_object("/secure/daemon/ping")){ + if(pinger->GetPinging()){ + pinger->SetOK(1); + } + } + tn("Auth reply received from "+packet[2]+".","white"); + tn("Ping packet: "+identify(packet),"white"); + if(sizeof(pingers)){ + foreach(object dude in pingers){ + tell_player(dude, packet[2]+" has just replied to a ping request from "+ + packet[4]+"."); + dude->SetProperty("pinging",0); + } + } + } + + void eventReceiveAuthRequest(mixed array packet) { + string mudlist = ""; + PING_D->SetOK(); + tn("Auth request received from "+packet[2]+".","white"); + INTERMUD_D->eventWrite( ({"auth-mud-reply", 5, mud_name(), 0, packet[2], + 0, (random(9999) * 10000) + 1138 }) ); + if(file_exists("/tmp/muds.txt")) + mudlist = read_file("/tmp/muds.txt"); + if(!grepp(mudlist,packet[2]) || packet[2] == "DeadSoulsNew" || + packet[2] == "DeadSoulsWin"){ + write_file("/tmp/muds.txt",packet[2]+"\n"); + tc("We have a new mud! "+packet[2]+" has joined intermud.","red"); + tn("We have a new mud! "+packet[2]+" has joined intermud.","red"); + } + + } + + diff -c -r --new-file ds1.1/lib/daemon/services/channel.c ds2.1/lib/daemon/services/channel.c *** ds1.1/lib/daemon/services/channel.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/services/channel.c Tue Jul 11 18:30:59 2006 *************** *** 9,93 **** #define SERVICE_CHANNEL #include <daemons.h> #include <message_class.h> void eventReceiveChannelWhoReply(mixed array packet) { object ob; if( file_name(previous_object()) != INTERMUD_D ) return; if( !(ob = find_player(packet[5])) ) return; packet[6] = (string)CHAT_D->GetLocalChannel(packet[6]); if( !sizeof(packet[7]) ) { ob->eventPrint("No one is listening to " + packet[6] + " at " + ! packet[2] + ".", MSG_SYSTEM); return; } ob->eventPrint("Listening to " + packet[6] + " at " + packet[2] + ":" + ! implode(packet[7], " "), MSG_SYSTEM); } void eventReceiveChannelWhoRequest(mixed array packet) { string array who; ! if( file_name(previous_object()) != INTERMUD_D ) return; who = (string array)CHAT_D->GetChannelList(packet[6]); INTERMUD_D->eventWrite(({ "chan-who-reply", 5, mud_name(), 0, packet[2], ! packet[3], packet[6], who })); } void eventReceiveChannelUserRequest(mixed array packet) { object ob; string visname; int gender; - if( file_name(previous_object()) != INTERMUD_D ) return; if( !(ob = find_player(packet[6])) ) { INTERMUD_D->eventWrite( ({ "error", 5, mud_name(), 0, packet[2], 0, ! "unk-user", packet[6] + " is not a valid " ! "player.", packet }) ); return; } visname = (string)ob->GetCapName(); switch( (string)ob->GetGender() ) { ! case "male": gender = 0; break; ! case "female": gender = 1; break; ! default: gender = 2; break; } INTERMUD_D->eventWrite( ({ "chan-user-reply", 5, mud_name(), 0, ! packet[2], 0, packet[6], visname, gender })); } void eventReceiveChannelMessage(mixed array packet) { if( file_name(previous_object()) != INTERMUD_D ) return; if( packet[2] == mud_name() ) return; CHAT_D->eventSendChannel(packet[7] + "@" + packet[2], packet[6], ! packet[8]); } void eventReceiveChannelEmote(mixed array packet) { if( file_name(previous_object()) != INTERMUD_D ) return; if( packet[2] == mud_name() ) return; if( !packet[7] ) return; CHAT_D->eventSendChannel(packet[7] + "@" + packet[2], packet[6], ! packet[8], 1, 0, 0); } void eventReceiveChannelTargettedEmote(mixed array packet) { string target; if( file_name(previous_object()) != INTERMUD_D ) return; if( packet[2] == mud_name() ) return; if( packet[7] != mud_name() ) target = packet[12] + "@" + packet[7]; else target = packet[12]; CHAT_D->eventSendChannel(packet[11] + "@" + packet[2], packet[6], ! packet[9], 1, target, packet[10]); } varargs void eventSendChannel(string who, string ch, string msg, int emote, ! string target, string targmsg) { mixed array packet; string targpl, where; // targpl is target keyname if( emote ) { if( target && targmsg ) { if( sscanf(target, "%s@%s", targpl, where) != 2 ) { --- 9,121 ---- #define SERVICE_CHANNEL #include <daemons.h> + #include <rooms.h> #include <message_class.h> + static private string *local_chans = ({"newbie","cre","gossip","admin","error", + "priest", "mage", "explorer", "thief", "fighter", "death" }); + + void eventReceiveChannelWhoReply(mixed array packet) { object ob; + tn("eventReceiveChannelWhoReply: "+identify(packet),"green"); if( file_name(previous_object()) != INTERMUD_D ) return; if( !(ob = find_player(packet[5])) ) return; packet[6] = (string)CHAT_D->GetLocalChannel(packet[6]); if( !sizeof(packet[7]) ) { ob->eventPrint("No one is listening to " + packet[6] + " at " + ! packet[2] + ".", MSG_SYSTEM); return; } ob->eventPrint("Listening to " + packet[6] + " at " + packet[2] + ":" + ! implode(packet[7], " "), MSG_SYSTEM); } void eventReceiveChannelWhoRequest(mixed array packet) { string array who; ! string ret = ""; if( file_name(previous_object()) != INTERMUD_D ) return; who = (string array)CHAT_D->GetChannelList(packet[6]); INTERMUD_D->eventWrite(({ "chan-who-reply", 5, mud_name(), 0, packet[2], ! packet[3], packet[6], who })); ! ! foreach(string entry in who){ ! ret += entry+", "; ! } ! ret = truncate(ret,2); ! tn("eventReceiveChannelWhoRequest: "+identify(packet),"green"); ! ! tell_room(ROOM_ARCH,"The Arch Room loudspeaker announces: \"%^BOLD%^CYAN%^"+capitalize(packet[3])+" at "+packet[2]+" has requested a list of users listening to channel "+packet[6]+". Replying with: %^BOLD%^GREEN%^"+ret+".%^RESET%^\""); } void eventReceiveChannelUserRequest(mixed array packet) { object ob; string visname; int gender; if( file_name(previous_object()) != INTERMUD_D ) return; + tn("eventReceiveChannelUserRequest: "+identify(packet),"green"); if( !(ob = find_player(packet[6])) ) { INTERMUD_D->eventWrite( ({ "error", 5, mud_name(), 0, packet[2], 0, ! "unk-user", packet[6] + " is not a valid " ! "player.", packet }) ); return; } visname = (string)ob->GetCapName(); switch( (string)ob->GetGender() ) { ! case "male": gender = 0; break; ! case "female": gender = 1; break; ! default: gender = 2; break; } INTERMUD_D->eventWrite( ({ "chan-user-reply", 5, mud_name(), 0, ! packet[2], 0, packet[6], visname, gender })); } void eventReceiveChannelMessage(mixed array packet) { + tn("eventReceiveChannelMessage: "+identify(packet),"green"); + if( file_name(previous_object()) != INTERMUD_D ) return; if( packet[2] == mud_name() ) return; + CHAT_D->eventSendChannel(packet[7] + "@" + packet[2], packet[6], ! packet[8]); ! if(packet[2] != mud_name()) CHAT_D->eventAddLast(packet[6],"",packet[6],packet[8],packet[7] + "@" + packet[2]); ! } void eventReceiveChannelEmote(mixed array packet) { + tn("eventReceiveChannelEmote: "+identify(packet),"green"); + if( file_name(previous_object()) != INTERMUD_D ) return; if( packet[2] == mud_name() ) return; if( !packet[7] ) return; CHAT_D->eventSendChannel(packet[7] + "@" + packet[2], packet[6], ! packet[8], 1, 0, 0); ! if(packet[2] != mud_name()) CHAT_D->eventAddLast(packet[6],"",packet[6],packet[7] + "@" + packet[2] + replace_string(packet[8],"$N","")); } void eventReceiveChannelTargettedEmote(mixed array packet) { string target; + tn("eventReceiveChannelTargettedEmote: "+identify(packet),"green"); if( file_name(previous_object()) != INTERMUD_D ) return; if( packet[2] == mud_name() ) return; if( packet[7] != mud_name() ) target = packet[12] + "@" + packet[7]; else target = packet[12]; CHAT_D->eventSendChannel(packet[11] + "@" + packet[2], packet[6], ! packet[9], 1, target, packet[10]); ! if(packet[2] != mud_name()) true(); } varargs void eventSendChannel(string who, string ch, string msg, int emote, ! string target, string targmsg) { mixed array packet; + mixed array packet_thing = ({ who, ch, msg, emote || "", target || "", targmsg || "" }); + string targpl, where; // targpl is target keyname + tn("eventSendChannel raw: "+identify( packet_thing ),"green"); + if( emote ) { if( target && targmsg ) { if( sscanf(target, "%s@%s", targpl, where) != 2 ) { *************** *** 95,112 **** where = mud_name(); } else { target = SERVICES_D->GetRemoteDisplayName(targpl, where); if( !target ) target = capitalize(targpl); } packet = ({ "channel-t", 5, mud_name(), convert_name(who), 0, 0, ! ch, where, targpl, msg, targmsg, who, target }); } else packet = ({ "channel-e", 5, mud_name(), convert_name(who), 0, 0, ! ch, who, msg }); } else packet = ({ "channel-m", 5, mud_name(), convert_name(who), 0, 0, ch, ! who, msg }); ! INTERMUD_D->eventWrite(packet); } void eventSendChannelWhoRequest(string channel, string mud) { --- 123,149 ---- where = mud_name(); } else { + where = trim(where); + if(!alphap(last(where,1))) where = truncate(where,1); + if(member_array(lower_case(where), INTERMUD_D->GetLCMuds()) == -1) { + write("No such mud."); + return; + } target = SERVICES_D->GetRemoteDisplayName(targpl, where); if( !target ) target = capitalize(targpl); } packet = ({ "channel-t", 5, mud_name(), convert_name(who), 0, 0, ! ch, where, targpl, msg, targmsg, who, target }); } else packet = ({ "channel-e", 5, mud_name(), convert_name(who), 0, 0, ! ch, who, msg }); } else packet = ({ "channel-m", 5, mud_name(), convert_name(who), 0, 0, ch, ! who, msg }); ! if(member_array(ch, local_chans) == -1){ ! INTERMUD_D->eventWrite(packet); ! tn("eventSendChannel processed: "+identify(packet),"green"); ! } } void eventSendChannelWhoRequest(string channel, string mud) { *************** *** 114,120 **** pl = (string)this_player(1)->GetKeyName(); INTERMUD_D->eventWrite(({ "chan-who-req", 5, mud_name(), pl, mud, 0, ! channel })); } void eventRegisterChannels(mapping list) { --- 151,158 ---- pl = (string)this_player(1)->GetKeyName(); INTERMUD_D->eventWrite(({ "chan-who-req", 5, mud_name(), pl, mud, 0, ! channel })); ! tn("eventSendChannelWhoRequest: "+identify( ({ "chan-who-req", 5, mud_name(), pl, mud, 0, channel })) , "green"); } void eventRegisterChannels(mapping list) { *************** *** 125,171 **** ns = (string)INTERMUD_D->GetNameserver(); foreach(channel, val in list) { if( !val ) continue; ! if( channel == (string)CHAT_D->GetLocalChannel(channel) ) { INTERMUD_D->eventWrite(({ "channel-listen", 5, mud_name(), 0, ns, ! 0, channel, 0 })); log_file("channels", "New channel: " + channel + " recognized " + ! ctime(time()) + "\nValue: " + identify(val) + "\n\n"); } else INTERMUD_D->eventWrite(({ "channel-listen", 5, mud_name(), 0, ns, ! 0, channel, 1 })); } } int eventAdministerChannel(string channel, string array additions, ! string array subs) { if( !((int)master()->valid_apply( ({}) )) ) return 0; if( member_array(channel, (string array)INTERMUD_D->GetChannels()) == -1 ) ! return 0; INTERMUD_D->eventWrite(({ "channel-admin", 5, mud_name(), ! (string)this_player(1)->GetKeyName(), ! (string)INTERMUD_D->GetNameserver(), ! 0, channel, additions, subs })); return 1; } int AddChannel(string channel, int privee) { ! if( !((int)master()->valid_apply( ({}) )) ) return 0; ! if( member_array(channel, (string array)INTERMUD_D->GetChannels()) != -1 ) ! return 0; INTERMUD_D->eventWrite(({ "channel-add", 5, mud_name(), ! (string)this_player(1)->GetKeyName(), ! (string)INTERMUD_D->GetNameserver(), 0, ! channel, privee })); return 1; } int RemoveChannel(string channel) { ! if( !((int)master()->valid_apply( ({}) )) ) return 0; ! if( member_array(channel, (string array)INTERMUD_D->GetChannels()) == -1 ) ! return 0; INTERMUD_D->eventWrite(({ "channel-remove", 5, mud_name(), ! (string)this_player(1)->GetKeyName(), ! (string)INTERMUD_D->GetNameserver(), 0, ! channel })); return 1; } --- 163,224 ---- ns = (string)INTERMUD_D->GetNameserver(); foreach(channel, val in list) { if( !val ) continue; ! if( channel == (string)CHAT_D->GetLocalChannel(channel) && ! channel != "dead_test4" && channel != "dead_souls" && ! channel != "lpuni" && channel != "german" ) { INTERMUD_D->eventWrite(({ "channel-listen", 5, mud_name(), 0, ns, ! 0, channel, 0 })); log_file("channels", "New channel: " + channel + " recognized " + ! ctime(time()) + "\nValue: " + identify(val) + "\n\n"); } else INTERMUD_D->eventWrite(({ "channel-listen", 5, mud_name(), 0, ns, ! 0, channel, 1 })); } + tn("eventRegisterChannels: "+identify(list),"green"); + } int eventAdministerChannel(string channel, string array additions, ! string array subs) { ! tn("eventAdministerChannel. ","green"); ! if( !((int)master()->valid_apply( ({}) )) ) return 0; if( member_array(channel, (string array)INTERMUD_D->GetChannels()) == -1 ) ! return 0; INTERMUD_D->eventWrite(({ "channel-admin", 5, mud_name(), ! (string)this_player(1)->GetKeyName(), ! (string)INTERMUD_D->GetNameserver(), ! 0, channel, additions, subs })); ! ! tn("eventAdministerChannel: "+channel+" "+identify(additions)+" "+identify(subs),"green"); return 1; } int AddChannel(string channel, int privee) { ! tn("eventAdministerChannel: "+channel+", "+privee,"green"); ! ! if( !((int)master()->valid_apply( ({}) )) ){ ! return 0; ! } ! if( member_array(channel, (string array)INTERMUD_D->GetChannels()) != -1 ){ ! return 0; ! } INTERMUD_D->eventWrite(({ "channel-add", 5, mud_name(), ! (string)this_player(1)->GetKeyName(), ! (string)INTERMUD_D->GetNameserver(), 0, ! channel, privee })); return 1; } int RemoveChannel(string channel) { ! tn("RemoveChannel: "+identify(channel),"green"); ! ! if( member_array(channel, (string array)INTERMUD_D->GetChannels()) == -1 ){ ! return 0; ! } INTERMUD_D->eventWrite(({ "channel-remove", 5, mud_name(), ! (string)this_player(1)->GetKeyName(), ! (string)INTERMUD_D->GetNameserver(), 0, ! channel })); return 1; } diff -c -r --new-file ds1.1/lib/daemon/services/emoteto.c ds2.1/lib/daemon/services/emoteto.c *** ds1.1/lib/daemon/services/emoteto.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/services/emoteto.c Wed Jul 5 00:01:03 2006 *************** *** 12,25 **** object ob; string who; if( file_name(previous_object()) != INTERMUD_D ) return; who = convert_name(packet[5]); if( !(ob = find_player(who)) || (int)ob->GetInvis() ) { INTERMUD_D->eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! capitalize(packet[5]) + " is nowhere to " ! "be found on " + mud_name() + ".", ! packet })); return; } packet[7] = replace_string(packet[7], "$N", packet[6] + "@" + packet[2]); --- 12,26 ---- object ob; string who; + tn("eventReceiveEmote: "+identify(packet), "green"); if( file_name(previous_object()) != INTERMUD_D ) return; who = convert_name(packet[5]); if( !(ob = find_player(who)) || (int)ob->GetInvis() ) { INTERMUD_D->eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! capitalize(packet[5]) + " is nowhere to " ! "be found on " + mud_name() + ".", ! packet })); return; } packet[7] = replace_string(packet[7], "$N", packet[6] + "@" + packet[2]); *************** *** 28,41 **** void eventSendEmote(string who, string where, string msg) { string pl, plc; ! pl = (string)this_player(1)->GetKeyName(); plc = (string)this_player(1)->GetCapName(); where = (string)INTERMUD_D->GetMudName(where); INTERMUD_D->eventWrite(({ "emoteto", 5, mud_name(), pl, where, ! convert_name(who), plc, msg })); } - ! --- 29,43 ---- void eventSendEmote(string who, string where, string msg) { string pl, plc; ! pl = (string)this_player(1)->GetKeyName(); plc = (string)this_player(1)->GetCapName(); where = (string)INTERMUD_D->GetMudName(where); INTERMUD_D->eventWrite(({ "emoteto", 5, mud_name(), pl, where, ! convert_name(who), plc, msg })); ! tn("eventSendEmote: "+identify( "emoteto", 5, mud_name(), pl, where,convert_name(who), plc, msg ),"green"); } ! ! diff -c -r --new-file ds1.1/lib/daemon/services/error.c ds2.1/lib/daemon/services/error.c *** ds1.1/lib/daemon/services/error.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/services/error.c Wed Jul 5 00:01:03 2006 *************** *** 8,13 **** --- 8,15 ---- object ob; string error_code, mud, target, msg; + tn("ERROR RECEIVED: "+identify(packet)); + if( packet[5] ) { target = convert_name(packet[5]); if( !(ob = find_player(target)) ) return; *************** *** 17,32 **** msg = packet[7]; packet = packet[8]; switch(error_code) { ! case "unk-dst": case "not-imp": case "unk-type": case "unk-src": log_file("errors/intermud", error_code + ": " + msg + "\n"); return; ! case "unk-type": log_file("errors/intermud", error_code + ": " + msg + "\n"); return; ! case "unk-user": if( !ob ) return; message("system", (msg ? msg : "Unknown user reported from " + mud + ! "."), ob); return; } } --- 19,34 ---- msg = packet[7]; packet = packet[8]; switch(error_code) { ! case "unk-dst": case "not-imp": case "unk-type": case "unk-src": log_file("errors/intermud", error_code + ": " + msg + "\n"); return; ! case "unk-type": log_file("errors/intermud", error_code + ": " + msg + "\n"); return; ! case "unk-user": if( !ob ) return; message("system", (msg ? msg : "Unknown user reported from " + mud + ! "."), ob); return; } } diff -c -r --new-file ds1.1/lib/daemon/services/finger.c ds2.1/lib/daemon/services/finger.c *** ds1.1/lib/daemon/services/finger.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/services/finger.c Wed Jul 5 00:01:03 2006 *************** *** 9,14 **** --- 9,15 ---- #define SERVICE_FINGER #include <daemons.h> + #include <rooms.h> #include <message_class.h> void eventReceiveFingerRequest(mixed array packet) { *************** *** 16,29 **** if( file_name(previous_object()) != INTERMUD_D ) return; if( !(ret = (mixed array)FINGER_D->GetRemoteFinger(packet[6])) ) { ! INTERMUD_D->eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! capitalize(packet[6]) + " is not involved.", ! packet })); return; } ret = ({ "finger-reply", 5, mud_name(), 0, packet[2], packet[3] }) + ret; INTERMUD_D->eventWrite(ret); } void eventReceiveFingerReply(mixed array packet) { --- 17,33 ---- if( file_name(previous_object()) != INTERMUD_D ) return; if( !(ret = (mixed array)FINGER_D->GetRemoteFinger(packet[6])) ) { ! INTERMUD_D->eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! capitalize(packet[6]) + " is not involved.", ! packet })); return; } ret = ({ "finger-reply", 5, mud_name(), 0, packet[2], packet[3] }) + ret; INTERMUD_D->eventWrite(ret); + tell_room(ROOM_ARCH,"The Arch Room loudspeaker announces: \"%^BOLD%^CYAN%^"+capitalize(packet[3])+" at "+packet[2]+" has requested finger information about "+capitalize(ret[6])+".%^RESET%^\""); + tn("eventReceiveFingerRequest: "+identify(packet),"cyan"); + } void eventReceiveFingerReply(mixed array packet) { *************** *** 45,54 **** fing += sprintf(" (idle %02d:%02d:%02d)\n", i/3600, (i/60)%60, i%60); } else fing += (packet[10] ? "Last logged in: " + packet[10] + "\n" : ! "Not logged in.\n"); fing += "Site: " + (packet[12] ? packet[12] : "Confidential") + "\n"; fing += (packet[14] ? packet[14] : "\n"); ob->eventPrint(fing, MSG_SYSTEM); } void eventSendFingerRequest(string who, string where) { --- 49,59 ---- fing += sprintf(" (idle %02d:%02d:%02d)\n", i/3600, (i/60)%60, i%60); } else fing += (packet[10] ? "Last logged in: " + packet[10] + "\n" : ! "Not logged in.\n"); fing += "Site: " + (packet[12] ? packet[12] : "Confidential") + "\n"; fing += (packet[14] ? packet[14] : "\n"); ob->eventPrint(fing, MSG_SYSTEM); + tn("eventReceiveFingerReply: "+identify(packet),"cyan"); } void eventSendFingerRequest(string who, string where) { *************** *** 56,60 **** if( !(pl = (string)this_player(1)->GetKeyName()) ) return; INTERMUD_D->eventWrite( ({ "finger-req", 5, mud_name(), pl, where, 0, ! who }) ); } --- 61,66 ---- if( !(pl = (string)this_player(1)->GetKeyName()) ) return; INTERMUD_D->eventWrite( ({ "finger-req", 5, mud_name(), pl, where, 0, ! who }) ); ! tn("eventSendFingerRequest: "+identify( ({ "finger-req", 5, mud_name(), pl, where, 0,who }) ),"cyan"); } diff -c -r --new-file ds1.1/lib/daemon/services/locate.c ds2.1/lib/daemon/services/locate.c *** ds1.1/lib/daemon/services/locate.c Sun Feb 1 21:29:58 1998 --- ds2.1/lib/daemon/services/locate.c Wed Jul 5 00:01:03 2006 *************** *** 9,14 **** --- 9,15 ---- #define SERVICE_LOCATE #include <daemons.h> + #include <rooms.h> #include <message_class.h> void eventReceiveLocateRequest(mixed array packet) { *************** *** 17,22 **** --- 18,25 ---- object ob; if( file_name(previous_object()) != INTERMUD_D ) return; + tell_room(ROOM_ARCH,"The Arch Room loudspeaker announces: \"%^BOLD%^CYAN%^"+capitalize(packet[3])+" at "+packet[2]+" has issued a locate request for %^BOLD%^YELLOW%^"+capitalize(packet[6])+".%^RESET%^\""); + tn("Locate request received: "+identify(packet),"white"); if( !(ob = find_player(packet[6])) || ob->GetInvis()) return; if( interactive(ob) ) { string array tmp = ({ }); *************** *** 29,36 **** } else status = "link-dead"; INTERMUD_D->eventWrite( ({ "locate-reply", 5, mud_name(), 0, packet[2], ! packet[3], mud_name(), ! (string)ob->GetName(), idl, status }) ); } void eventReceiveLocateReply(mixed array packet) { --- 32,39 ---- } else status = "link-dead"; INTERMUD_D->eventWrite( ({ "locate-reply", 5, mud_name(), 0, packet[2], ! packet[3], mud_name(), ! (string)ob->GetName(), idl, status }) ); } void eventReceiveLocateReply(mixed array packet) { *************** *** 41,46 **** --- 44,50 ---- if( file_name(previous_object()) != INTERMUD_D ) return; if( !stringp(packet[5]) || !(ob = find_player(convert_name(packet[5]))) ) return; + tn("Locate reply received: "+identify(packet),"white"); m = packet[7] + " was just located on " + packet[6] + "."; if( (idl = (int)packet[8]) > 60 ) m += sprintf(" (idle %02d:%02d:%02d)", idl/3600, (idl/60)%60, idl%60); *************** *** 51,57 **** void eventSendLocateRequest(string who) { string pl; ! if( !(pl = (string)this_player(1)->GetKeyName()) ) return; INTERMUD_D->eventWrite( ({ "locate-req", 5, mud_name(), pl, 0, 0, who }) ); } --- 55,62 ---- void eventSendLocateRequest(string who) { string pl; ! mixed *locate_request = ({ "locate-req", 5, mud_name(), pl, 0, 0, who }); if( !(pl = (string)this_player(1)->GetKeyName()) ) return; INTERMUD_D->eventWrite( ({ "locate-req", 5, mud_name(), pl, 0, 0, who }) ); + tn("Locate request being sent: "+identify(locate_request),"white"); } diff -c -r --new-file ds1.1/lib/daemon/services/tell.c ds2.1/lib/daemon/services/tell.c *** ds1.1/lib/daemon/services/tell.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/services/tell.c Wed Jul 5 00:01:03 2006 *************** *** 10,46 **** #include <message_class.h> void eventReceiveTell(mixed *packet) { ! object ob; string who; if( file_name(previous_object()) != INTERMUD_D ) return; who = convert_name(packet[5]); if( !(ob = find_player(who)) || (int)ob->GetInvis() ) { INTERMUD_D->eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! capitalize(packet[5]) + " is nowhere to " ! "be found on " + mud_name() + ".", ! packet })); ! return; } ob->eventPrint("%^BOLD%^RED%^" + packet[6] + "@" + packet[2] + ! " tells you:%^RESET%^ " + packet[7], MSG_CONV); ! ob->SetProperty("reply", packet[6] + "@" + packet[2]); } void eventSendTell(string who, string where, string msg) { string pl, plc; ! pl = (string)this_player(1)->GetName(); plc = (string)this_player(1)->GetCapName(); where = (string)INTERMUD_D->GetMudName(where); INTERMUD_D->eventWrite(({ "tell", 5, mud_name(), pl, where, ! convert_name(who), plc, msg })); this_player(1)->eventPrint("%^BOLD%^RED%^You tell " + capitalize(who) + ! "@" + where + ":%^RESET%^ " + msg, ! MSG_CONV); } - ! --- 10,68 ---- #include <message_class.h> void eventReceiveTell(mixed *packet) { ! object ob, machine; string who; + string adverb = ""; + tn("eventReceiveTell: "+identify(packet),"yellow"); if( file_name(previous_object()) != INTERMUD_D ) return; who = convert_name(packet[5]); if( !(ob = find_player(who)) || (int)ob->GetInvis() ) { INTERMUD_D->eventWrite(({ "error", 5, mud_name(), 0, packet[2], ! packet[3], "unk-user", ! capitalize(packet[5]) + " is nowhere to " ! "be found on " + mud_name() + ".", ! packet })); ! if(!(ob = find_player(who))) return; ! adverb = " %^BOLD%^MAGENTA%^unknowingly%^BOLD%^RED%^"; } + + machine=present("answering machine",ob); + if(machine && base_name(machine) == "/secure/obj/machine"){ + int parse_it; + string machine_message; + parse_it=machine->query_answer(); + if(parse_it && !(int)ob->GetInvis()){ + machine->get_message(packet[6] + "@" + packet[2]+ + " tells you: "+packet[7]+"\n"); + machine_message=machine->send_message(); + INTERMUD_D->eventWrite(({ "error", 5, mud_name(), 0, packet[2], + packet[3], "unk-user", + machine_message, + packet })); + return; + } + } + ob->eventPrint("%^BOLD%^RED%^" + packet[6] + "@" + packet[2] + ! adverb + " tells you:%^RESET%^ " + packet[7], MSG_CONV); ! if(!sizeof(adverb)) ob->SetProperty("reply", packet[6] + "@" + packet[2]); } void eventSendTell(string who, string where, string msg) { string pl, plc; ! pl = (string)this_player(1)->GetName(); plc = (string)this_player(1)->GetCapName(); where = (string)INTERMUD_D->GetMudName(where); INTERMUD_D->eventWrite(({ "tell", 5, mud_name(), pl, where, ! convert_name(who), plc, msg })); this_player(1)->eventPrint("%^BOLD%^RED%^You tell " + capitalize(who) + ! "@" + where + ":%^RESET%^ " + msg, ! MSG_CONV); ! tn("eventSendTell: "+identify( ({ "tell", 5, mud_name(), pl, where, convert_name(who), plc, msg }) ), "yellow"); } ! ! diff -c -r --new-file ds1.1/lib/daemon/services/ucache.c ds2.1/lib/daemon/services/ucache.c *** ds1.1/lib/daemon/services/ucache.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/services/ucache.c Wed Dec 31 19:00:00 1969 *************** *** 1,99 **** - /* /daemon/services/ucache.c - * From the Dead Souls V Object Library - * Intermud 3 ucache service implementation - * created by Tim 961211 - * Version: @(#) ucache.c 1.2@(#) - * Last modified: 96/12/14 - */ - - #define SERVICE_UCACHE - - // Number of days until an item is removed from the cache - #define UCACHE_INFO_LIFETIME 4 - - class uinfo { - string Visname; - int Gender; - int TimeStamp; - } - - private mapping Ucache = ([ ]); - - void eventReceiveUcacheUpdate(mixed array packet) { - string mud = packet[2], user = packet[6]; - class uinfo ui; - - if( file_name(previous_object()) != INTERMUD_D ) return; - if( !Ucache[mud] ) Ucache[mud] = ([ ]); - if( !(ui = Ucache[mud][user]) ) Ucache[mud][user] = ui = new(class uinfo); - ui->Visname = (string)packet[7]; - ui->Gender = (int)packet[8]; - ui->TimeStamp = time(); - } - - static void eventSendChannelUserRequest(string who, string where) { - string pl; - - INTERMUD_D->eventWrite( ({ "chan-user-req", 5, mud_name(), 0, where, 0, - who }) ); - } - - void eventClearUcache() { - if( this_player(1) && !archp(this_player(1)) ) return; - Ucache = ([ ]); - } - - void eventDisplayUcache(object agent) { - string array lines; - - if( !agent || (this_player(1) && !archp(this_player(1))) ) return; - lines = ({ "Mud User VisName Gender" }); - foreach(string mud, mapping uc in Ucache) { - foreach(string user, class uinfo ui in uc) - lines += ({ sprintf("%-:10s %-:10s %-:10s %d", - mud, user, ui->Visname, ui->Gender) }); - } - agent->eventPage(lines); - } - - static void eventCompactUcache() { - int ts = time() - (UCACHE_INFO_LIFETIME * 3600 * 24); - - foreach(string mud, mapping uc in Ucache) { - foreach(string user, class uinfo ui in uc) - if( ui->TimeStamp < ts ) map_delete(uc, user); - } - eventSave(); - call_out((: eventCompactUcache :), 3600); - } - - string GetRemoteDisplayName(string user, string mud) { - class uinfo ui; - - if( !Ucache[mud] || !(ui = Ucache[mud][user]) ) { - eventSendChannelUserRequest(user, mud); - return 0; - } - else { - ui->TimeStamp = time(); - return ui->Visname; - } - } - - string GetRemoteGender(string user, string mud) { - class uinfo ui; - - if( !Ucache[mud] || !(ui = Ucache[mud][user]) ) { - eventSendChannelUserRequest(user, mud); - return 0; - } - else { - ui->TimeStamp = time(); - switch( ui->Gender ) { - case 0: return "male"; - case 1: return "female"; - case 2: return "neuter"; - default: return 0; - } - } - } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/services/who.c ds2.1/lib/daemon/services/who.c *** ds1.1/lib/daemon/services/who.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/services/who.c Tue Jul 11 18:30:59 2006 *************** *** 7,43 **** #define SERVICE_WHO #include <daemons.h> void eventReceiveWhoReply(mixed *packet) { ! string *list, *who; object ob; if( file_name(previous_object()) != INTERMUD_D ) return; if( !packet[5] || !(ob = find_player(convert_name(packet[5]))) ) return; ! list = ({ "Remote who information from " + packet[2] + ":" }); foreach(who in packet[6]) ! list += ({ who[0] + " (" + who[1] + " idle): " + who[2] }); ! ob->eventPage(list); } void eventReceiveWhoRequest(mixed *packet) { mixed *msg; ! if( file_name(previous_object()) != INTERMUD_D ) return; ! msg = map(filter(users(), (: !((int)$1->GetInvis()) :)), ! (: ({ (string)$1->GetCapName(), query_idle($1), ! (string)$1->GetShort() }) :)); INTERMUD_D->eventWrite(({ "who-reply", 5, mud_name(), 0, packet[2], ! packet[3], msg })); } void eventSendWhoRequest(string mud) { string who; ! who = (string)this_player(1)->GetName(); INTERMUD_D->eventWrite(({ "who-req", 5, mud_name(), who, mud, 0 })); } - ! --- 7,52 ---- #define SERVICE_WHO #include <daemons.h> + #include <rooms.h> void eventReceiveWhoReply(mixed *packet) { ! string list, *who; object ob; if( file_name(previous_object()) != INTERMUD_D ) return; if( !packet[5] || !(ob = find_player(convert_name(packet[5]))) ) return; ! list = "%^MAGENTA%^Remote who information from " + packet[2] + ":%^RESET%^\n"; foreach(who in packet[6]) ! list += who[0] + " (" + who[1] + " idle): " + who[2] +"\n"; ! ob->eventPrint(list); ! tn("eventReceiveWhoReply: "+identify(packet),"blue"); } void eventReceiveWhoRequest(mixed *packet) { mixed *msg; ! string ret = ""; if( file_name(previous_object()) != INTERMUD_D ) return; ! msg = map(filter(users(), (: (environment($1) && !((int)$1->GetInvis())) :)), ! (: ({ (string)$1->GetCapName(), query_idle($1), ! (string)$1->GetShort() }) :)); INTERMUD_D->eventWrite(({ "who-reply", 5, mud_name(), 0, packet[2], ! packet[3], msg })); ! foreach(string *entry in msg){ ! ret += entry[0]+", "; ! } ! ret = truncate(ret,2); ! tn("eventReceiveWhoRequest: "+identify(packet),"blue"); ! tell_room(ROOM_ARCH,"The Arch Room loudspeaker announces: \"%^BOLD%^CYAN%^"+capitalize(packet[3])+" at "+packet[2]+" has requested a list of users currently logged on. Replying with: %^BOLD%^YELLOW%^"+ret+".%^RESET%^\""); } void eventSendWhoRequest(string mud) { string who; ! who = (string)this_player(1)->GetKeyName(); INTERMUD_D->eventWrite(({ "who-req", 5, mud_name(), who, mud, 0 })); + tn("eventSendWhoRequest: "+identify( ({ "who-req", 5, mud_name(), who, mud, 0 })), "blue"); } ! ! diff -c -r --new-file ds1.1/lib/daemon/services.c ds2.1/lib/daemon/services.c *** ds1.1/lib/daemon/services.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/services.c Wed Jul 5 00:00:58 2006 *************** *** 25,31 **** #include "/daemon/services/locate.c" #include "/daemon/services/tell.c" #include "/daemon/services/who.c" ! #include "/daemon/services/ucache.c" static void create() { SetSaveFile(SAVE_SERVICES); --- 25,31 ---- #include "/daemon/services/locate.c" #include "/daemon/services/tell.c" #include "/daemon/services/who.c" ! #include "/daemon/services/auth.c" static void create() { SetSaveFile(SAVE_SERVICES); *************** *** 44,97 **** mapping GetServices() { return ([ #ifdef SERVICE_AUTH ! "auth" : 1, #endif #ifdef SERVICE_CHANNEL ! "channel" : 1, #endif #ifdef SERVICE_EMOTETO ! "emoteto" : 1, #endif #ifdef SERVICE_FILE ! "file" : 1, #endif #ifdef SERVICE_FINGER ! "finger" : 1, #endif #ifdef SERVICE_LOCATE ! "locate" : 1, #endif #ifdef SERVICE_MAIL ! "mail" : 1, #endif #ifdef SERVICE_NEWS ! "news" : 1, #endif #ifdef SERVICE_TELL ! "tell" : 1, #endif #ifdef SERVICE_UCACHE ! "ucache" : 1, #endif #ifdef SERVICE_WHO ! "who" : 1, #endif #ifdef PORT_FTP ! "ftp" : PORT_FTP, #endif #ifdef PORT_HTTP ! "http" : PORT_HTTP, #endif #ifdef PORT_NNTP ! "nntp" : PORT_NNTP, #endif #ifdef PORT_RCP ! "rcp" : PORT_RCP, #endif #ifdef PORT_SMTP ! "smtp" : PORT_SMTP, #endif ! ]); } #endif /* __PACKAGE_SOCKETS__ */ --- 44,97 ---- mapping GetServices() { return ([ #ifdef SERVICE_AUTH ! "auth" : 1, #endif #ifdef SERVICE_CHANNEL ! "channel" : 1, #endif #ifdef SERVICE_EMOTETO ! "emoteto" : 1, #endif #ifdef SERVICE_FILE ! "file" : 1, #endif #ifdef SERVICE_FINGER ! "finger" : 1, #endif #ifdef SERVICE_LOCATE ! "locate" : 1, #endif #ifdef SERVICE_MAIL ! "mail" : 1, #endif #ifdef SERVICE_NEWS ! "news" : 1, #endif #ifdef SERVICE_TELL ! "tell" : 1, #endif #ifdef SERVICE_UCACHE ! "ucache" : 1, #endif #ifdef SERVICE_WHO ! "who" : 1, #endif #ifdef PORT_FTP ! "ftp" : PORT_FTP, #endif #ifdef PORT_HTTP ! "http" : PORT_HTTP, #endif #ifdef PORT_NNTP ! "nntp" : PORT_NNTP, #endif #ifdef PORT_RCP ! "rcp" : PORT_RCP, #endif #ifdef PORT_SMTP ! "smtp" : PORT_SMTP, #endif ! ]); } #endif /* __PACKAGE_SOCKETS__ */ diff -c -r --new-file ds1.1/lib/daemon/soul.c ds2.1/lib/daemon/soul.c *** ds1.1/lib/daemon/soul.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/soul.c Wed Jul 5 00:00:58 2006 *************** *** 1,5 **** /* /daemon/emote.c ! * From the Dead Souls V Object Library * A centralized soul handler * Created by Descartes of Borg 961207 * Version: @(#) soul.c 1.11@(#) --- 1,5 ---- /* /daemon/emote.c ! * From the Dead Souls Object Library * A centralized soul handler * Created by Descartes of Borg 961207 * Version: @(#) soul.c 1.11@(#) *************** *** 34,43 **** } varargs int AddRule(string verb, string rle, mixed array msg, ! string array advs) { class emote e = Emotes[verb]; class rule r; ! if( !e ) { return 0; } --- 34,43 ---- } varargs int AddRule(string verb, string rle, mixed array msg, ! string array advs) { class emote e = Emotes[verb]; class rule r; ! if( !e ) { return 0; } *************** *** 70,76 **** int RemoveRule(string emt, string rle) { class emote e = Emotes[emt]; ! if( !master()->valid_apply(({ PRIV_ASSIST })) ) { return 0; } --- 70,76 ---- int RemoveRule(string emt, string rle) { class emote e = Emotes[emt]; ! if( !master()->valid_apply(({ PRIV_ASSIST })) ) { return 0; } *************** *** 99,105 **** class emote e = Emotes[emote]; mapping adverb = ([]); class rule r; ! if( !e ) { return 0; } --- 99,105 ---- class emote e = Emotes[emote]; mapping adverb = ([]); class rule r; ! if( !e ) { return 0; } *************** *** 125,136 **** return 0; } adverb = ([ "$adverb" : matches[0] ]); - } - else { - adverb = ([ "$adverb" : args ]); - } } ! return ({ r->Message, adverb }); } string array GetEmotes() { --- 125,136 ---- return 0; } adverb = ([ "$adverb" : matches[0] ]); } ! else { ! adverb = ([ "$adverb" : args ]); ! } ! } ! return ({ r->Message, adverb }); } string array GetEmotes() { *************** *** 153,171 **** if( arg == "soul" ) { str = "Your \"soul\" is a system of expressions you can use " ! "to express how you are feeling. Though it does not really " ! "cause anything to happen, other people, including NPC's, may " ! "react to your emotions, especially when they are violent or " ! "negative.\n\n" ! "Some soul commands allow you to express an adverb to give some " ! "sort of emphasis to the expression. Some commands are limited " ! "to a certain set of adverbs, while most commands will allow you " ! "to choose from the list of system wide adverbs given below. " ! "You may always use your racial adverb in any expression " ! "allowing an adverb. A racial adverb is simply a way of " ! "emoting unique to your race, like \"smile gnomishly\".\n\n" ! "For a list of soul commands, try <help feelings>.\n\n" ! "The list of system adverbs are:\n"; str += format_page(sort_array(Adverbs, 1), 5); return str; } --- 153,171 ---- if( arg == "soul" ) { str = "Your \"soul\" is a system of expressions you can use " ! "to express how you are feeling. Though it does not really " ! "cause anything to happen, other people, including NPC's, may " ! "react to your emotions, especially when they are violent or " ! "negative.\n\n" ! "Some soul commands allow you to express an adverb to give some " ! "sort of emphasis to the expression. Some commands are limited " ! "to a certain set of adverbs, while most commands will allow you " ! "to choose from the list of system wide adverbs given below. " ! "You may always use your racial adverb in any expression " ! "allowing an adverb. A racial adverb is simply a way of " ! "emoting unique to your race, like \"smile gnomishly\".\n\n" ! "For a list of soul commands, try <help feelings>.\n\n" ! "The list of system adverbs are:\n"; str += format_page(sort_array(Adverbs, 1), 5); return str; } *************** *** 198,204 **** int all_advs = (member_array("-", r->Adverbs) != -1); int anything = (member_array("*", r->Adverbs) != -1); string rule = rls[0]; ! rule = replace_string(rule, "LIV", "SINGLE_LIVING"); rule = replace_string(rule, "LVS", "ONE_OR_MORE_LIVINGS"); if( anything ) { --- 198,204 ---- int all_advs = (member_array("-", r->Adverbs) != -1); int anything = (member_array("*", r->Adverbs) != -1); string rule = rls[0]; ! rule = replace_string(rule, "LIV", "SINGLE_LIVING"); rule = replace_string(rule, "LVS", "ONE_OR_MORE_LIVINGS"); if( anything ) { *************** *** 252,261 **** str += capitalize(arg) + " is a soul command and affects nothing.\n"; str += "System adverbs are listed in <help soul>.\n"; str += "SINGLE_LIVING: You can target a single living thing\n" ! "ONE_OR_MORE_LIVINGS: You can target multiple people using \"all\"\n" ! "PHRASE: Any random phrase\n" ! "ADVERB: Any adverb from the list of supported adverbs, or your " ! "racial adverb."; return str; } --- 252,261 ---- str += capitalize(arg) + " is a soul command and affects nothing.\n"; str += "System adverbs are listed in <help soul>.\n"; str += "SINGLE_LIVING: You can target a single living thing\n" ! "ONE_OR_MORE_LIVINGS: You can target multiple people using \"all\"\n" ! "PHRASE: Any random phrase\n" ! "ADVERB: Any adverb from the list of supported adverbs, or your " ! "racial adverb."; return str; } *************** *** 277,285 **** if( objectp(who) ) { res = who->GetRace(); } ! else { ! res == who; ! } if( !res ) { return "godly"; } --- 277,283 ---- if( objectp(who) ) { res = who->GetRace(); } ! if( !res ) { return "godly"; } *************** *** 296,302 **** mapping GetRules(string emote) { class emote e = Emotes[emote]; mapping m = ([]); ! if( !e ) { return 0; } --- 294,300 ---- mapping GetRules(string emote) { class emote e = Emotes[emote]; mapping m = ([]); ! if( !e ) { return 0; } *************** *** 321,327 **** mixed can_verb_rule(string verb, string rle) { class emote e = Emotes[verb]; class rule r; - mixed array msg; if( !e ) { return 0; --- 319,324 ---- *************** *** 338,344 **** class emote e = Emotes[verb]; class rule r = e->Rules[rle]; string adv = 0; ! switch( rle ) { case "": args = 0; --- 335,341 ---- class emote e = Emotes[verb]; class rule r = e->Rules[rle]; string adv = 0; ! switch( rle ) { case "": args = 0; *************** *** 400,412 **** if( !sizeof(matches) ) { this_player()->eventPrint("You cannot " + verb + " " + adv + ! "!"); return 1; } adv = matches[0]; } send_messages(r->Message[0], r->Message[1], this_player(), args, env, ! ([ "$adverb" : adv ])); if( args ) { args->eventReceiveEmote(this_player(), verb, adv); } --- 397,409 ---- if( !sizeof(matches) ) { this_player()->eventPrint("You cannot " + verb + " " + adv + ! "!"); return 1; } adv = matches[0]; } send_messages(r->Message[0], r->Message[1], this_player(), args, env, ! ([ "$adverb" : adv ])); if( args ) { args->eventReceiveEmote(this_player(), verb, adv); } diff -c -r --new-file ds1.1/lib/daemon/spells.c ds2.1/lib/daemon/spells.c *** ds1.1/lib/daemon/spells.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/spells.c Wed Jul 5 00:00:58 2006 *************** *** 27,33 **** spells = get_dir(DIR_SPELLS "/*.c"); foreach(string spell in spells) { object ob = find_object(DIR_SPELLS "/" + spell); ! if( ob ) { ob->eventDestruct(); } --- 27,33 ---- spells = get_dir(DIR_SPELLS "/*.c"); foreach(string spell in spells) { object ob = find_object(DIR_SPELLS "/" + spell); ! if( ob ) { ob->eventDestruct(); } diff -c -r --new-file ds1.1/lib/daemon/stargate.c ds2.1/lib/daemon/stargate.c *** ds1.1/lib/daemon/stargate.c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/daemon/stargate.c Tue Jul 11 18:30:59 2006 *************** *** 0 **** --- 1,132 ---- + /** + * stargate_d : stargate daemon. tracks the entire stargate network. + * started 2006-03-23 by jonez + * + * 2006-03-24, jonez + * - with help from cratylus, changed the daemon so it saves it's state + * whenever there is a change, and tries to load from disk at create + * time. + * 2006-03-28, jonez + * - gate is status is now "idle", "outbound", or "inbound". gate cannot be entered from the inbound side. + */ + + #include <lib.h> + #include <save.h> + #include "/daemon/include/stargate.h" + + inherit LIB_DAEMON; + + private mapping Stargates = ([]); + + static void create(){ + daemon::create(); + SetNoClean(1); + eventLoad(); + if (!Stargates) Stargates = ([]); + } + + void eventSave(){ + unguarded( (: save_object, SAVE_STARGATE, 1 :) ); + return; + } + + void eventLoad(){ + if (file_size(SAVE_STARGATE __SAVE_EXTENSION__) > 0){ + unguarded( (: restore_object, SAVE_STARGATE :) ); + } + return; + } + + int SetStargate(string address, string destination){ + mapping tmp = ([]); + Stargates[address] = tmp; + if (address == "" || destination == "") return 1; + if(sizeof(Stargates[address])) return 1; + Stargates[address]["status"] = "idle"; + Stargates[address]["destination"] = destination; + Stargates[address]["endpoint"] = ""; + eventSave(); + return 0; + } + + mapping GetStargate(string address){ + return copy(Stargates[address]); + } + + int RemoveStargate(string address){ + map_delete(Stargates, address); + eventSave(); + return 0; + } + + mapping GetStargates(){ + return copy(Stargates); + } + + int SetStatus(string address, string status){ + Stargates[address]["status"] = status; + eventSave(); + return 0; + } + + string GetStatus(string address){ + return Stargates[address]["status"]; + } + + string GetDestination(string address){ + string ret = Stargates[address]; + if(sizeof(Stargates[address]) && sizeof(Stargates[address]["destination"])) + return Stargates[address]["destination"]; + else return ""; + } + + string GetEndpoint(string address){ + return Stargates[address]["endpoint"]; + } + + int eventConnect(string from, string to){ + + if (from == to) return 0; + + if (!Stargates[from] || !sizeof(Stargates[from])){ + return 0; + } + + if (!Stargates[to] || !sizeof(Stargates[to])){ + return 0; + } + + if (Stargates[from]["status"] == "idle" && Stargates[to]["status"] == "idle"){ + + Stargates[from]["endpoint"] = to; + Stargates[from]["status"] = "outbound"; + + Stargates[to]["endpoint"] = from; + Stargates[to]["status"] = "inbound"; + eventSave(); + + return 1; + } + return 0; + } + + int eventDisconnect(string from){ + string endpoint; + if(!from || from == "") return 0; + + if (!Stargates[from] || !sizeof(Stargates[from])) return 0; + + endpoint = Stargates[from]["endpoint"]; + if (!endpoint) return 0; + + if(sizeof(Stargates[endpoint])){ + Stargates[endpoint]["endpoint"] = ""; + Stargates[endpoint]["status"] = "idle"; + } + + Stargates[from]["endpoint"] = ""; + Stargates[from]["status"] = "idle"; + + eventSave(); + return 1; + } diff -c -r --new-file ds1.1/lib/daemon/statistics.c ds2.1/lib/daemon/statistics.c *** ds1.1/lib/daemon/statistics.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/statistics.c Wed Jul 5 00:00:58 2006 *************** *** 1,5 **** /* /daemon/statistics.c ! * from the Dead Souls V Object Library * Keeps track of RAM intensive data on players * created by Descartes of Borg 951217 * Version: @(#) statistics.c 1.2@(#) --- 1,5 ---- /* /daemon/statistics.c ! * from the Dead Souls Object Library * Keeps track of RAM intensive data on players * created by Descartes of Borg 951217 * Version: @(#) statistics.c 1.2@(#) *************** *** 38,44 **** mapping GetKills(string who) { string file; ! who = convert_name(who); file = DIR_KILLS "/" + who[0..0] + "/" + who; if( unguarded((: file_size, file :)) < 1 ) return ([]); --- 38,44 ---- mapping GetKills(string who) { string file; ! who = convert_name(who); file = DIR_KILLS "/" + who[0..0] + "/" + who; if( unguarded((: file_size, file :)) < 1 ) return ([]); diff -c -r --new-file ds1.1/lib/daemon/terminal.c ds2.1/lib/daemon/terminal.c *** ds1.1/lib/daemon/terminal.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/terminal.c Wed Jul 5 00:00:58 2006 *************** *** 18,94 **** void create() { mapping nohtml; ! daemon::create(); SetNoClean(1); nohtml = ([ "BR": "", "P" : "", "/P" : "", "HREF" : "", ">" : "", ! "NAME" : "", "/A" : "", "I" : "", "/I" : "", "PRE" : "", ! "/PRE" : "", "STRONG" : "", "/STRONG" : "", "TABLE" : "", ! "/TABLE" : "", "TR" : "", "/TR" : "", "TD" : "", "/TD" : ""]); term_info = ([ ]); term_info["unknown"] = ! ([ "RESET": "", "BOLD": "", "FLASH":"", "BLACK":"", "RED":"", ! "BLUE":"", "CYAN":"", "MAGENTA":"", "ORANGE":"", "YELLOW":"", ! "GREEN":"", "WHITE":"", "BLACK":"", "B_RED":"", "B_ORANGE":"", ! "B_YELLOW":"", "B_BLACK":"", "B_CYAN":"","B_WHITE":"", "B_GREEN":"", ! "B_MAGENTA":"", "STATUS":"", "WINDOW":"", "INITTERM": "", ! "ENDTERM":""]) + nohtml; term_info["ansi"] = ! ([ "RESET":ANSI("0"), "BOLD":ANSI(1), "FLASH":ANSI(5), ! "BLACK":ANSI(30), "RED":ANSI(31), "GREEN":ANSI(32), ! "ORANGE":ANSI(33), "YELLOW":ANSI(1)+ANSI(33), "BLUE": ANSI(34), ! "CYAN":ANSI(36), "MAGENTA":ANSI(35), "BLACK":ANSI(30), ! "WHITE": ANSI(37), "B_RED":ANSI(41), "B_GREEN":ANSI(42), ! "B_ORANGE":ANSI(43), "B_YELLOW":ANSI(1)+ANSI(43), "B_BLUE":ANSI(44), ! "B_CYAN":ANSI(46), "B_BLACK":ANSI(40), "B_WHITE": ANSI(47), ! "CLEARLINE":ESC("[L")+ESC("[G"), "B_MAGENTA":ANSI(45), "STATUS":"", ! "WINDOW":"", "INITTERM":ESC("[H")+ESC("[2J"), "ENDTERM":"" ]) + ! nohtml; term_info["freedom"] = ! ([ "RESET": ESC("G0"), "BOLD":ESC("G@"), "FLASH":ESC("G2"), ! "BLACK":"", "RED":"", "GREEN":"", "ORANGE":"", "YELLOW":"", "BLUE":"", ! "CYAN":"", "MAGENTA":"", "BLACK":"", "WHITE":"", "B_RED":ESC("GD"), ! "B_GREEN": ESC("GD"), "B_ORANGE":ESC("G4"), "B_YELLOW":ESC("G4"), ! "B_BLUE":ESC("G4"), "B_CYAN":ESC("GD"), "B_BLACK": ESC("GD"), ! "B_WHITE":ESC("G4"), "B_MAGENTA":("G4"), "STATUS":"", "WINDOW":"", ! "CLEARLINE":"\r", "INITTERM":"", "ENDTERM":"" ]) + nohtml; term_info["ansi-status"] = ! ([ "RESET": ANSI("0;37;40"), "BOLD":ANSI(1), "FLASH":ANSI(5), ! "BLACK":ANSI(30), "RED":ANSI(31), "GREEN":ANSI(32), "ORANGE":ANSI(33), ! "YELLOW":ANSI(33), "BLUE":ANSI(34), "CYAN": ANSI(36), ! "MAGENTA": ANSI(35), "BLACK":ANSI(30), "WHITE":ANSI(37), ! "B_RED":ANSI(41), "B_GREEN":ANSI(42), "B_ORANGE":ANSI(43), ! "B_YELLOW": ANSI(1)+ANSI(43), "B_BLUE":ANSI(44), ! "B_CYAN": ANSI(46), "B_BLACK":ANSI(40), "B_WHITE":ANSI(47), ! "B_MAGENTA":ANSI(45), "STATUS":ESC("[23;24r")+ESC(8), ! "WINDOW":ESC(7)+ESC("[0;22r")+ESC("[22H\n"), ! "INITTERM":ESC("[H")+ESC("[J")+ESC("[23;24r")+ESC("23H\n"), ! "CLEARLINE":"\r", "ENDTERM":ESC("[0r")+ESC("[H")+ESC("[J") ]) +nohtml; ! term_info["xterm"] = ! ([ "RESET" : ANSI("0;37;40"), "BOLD": ESC("[7m"), ! "FLASH":ESC("[5m$<2>"), "BLACK":ANSI(30), "RED":ANSI(31), ! "GREEN":ANSI(32), "ORANGE":ANSI(33), "YELLOW":ANSI(33), ! "BLUE":ANSI(34), "CYAN":ANSI(36), "MAGENTA":ANSI(35),"BLACK":ANSI(34), ! "WHITE":ANSI(38), "B_RED":ANSI(41), "B_GREEN":ANSI(42), ! "B_ORANGE":ANSI(43), "B_YELLOW":ANSI(43), "B_BLUE":ANSI(44), ! "B_CYAN":ANSI(46), "B_BLACK":ANSI(40), "B_WHITE": ANSI(47), ! "B_MAGENTA": ANSI(45), "STATUS":"", "WINDOW":"", "INITTERM":"", ! "CLEARLINE":"\r", "ENDTERM":"" ]) + nohtml; ! term_info["html"] = term_info["unknown"] + ! ([ "RED" : "<FONT COLOR=\"#FF0000\">", ! "GREEN" : "<FONT COLOR=\"#00FF00\">", ! "BLUE" : "<FONT COLOR=\"#0000FF\">", ! "YELLOW" : "<FONT COLOR=\"#FFFF00\">", ! "CYAN" : "<FONT COLOR=\"#00A0DD\">", ! "MAGENTA" : "<FONT COLOR=\"#C50067\">", ! "YELLOW" : "<FONT COLOR=\"#FFFF00\">", ! "RESET": "</FONT>", ! "BR" : "<BR>", "P" : "<P>", "/P" : "</P>", ">" : ">", ! "HREF" : "<A HREF=", "NAME" : "<A NAME=", "/A" : "</A>", ! "I" : "<I>", "/I" : "</I>", "PRE" : "</PRE>", "/PRE" : "</PRE>", ! "STRONG" : "<STRONG>", "/STRONG" : "</STRONG>", ! "TABLE" : "<TABLE>", "/TABLE" : "</TABLE>", "TR" : "<TR>", ! "/TR" : "</TR>", "TD" : "<TD>" , "/TD" : "</TD>" ]); } mapping query_term_info(string type) { --- 18,94 ---- void create() { mapping nohtml; ! daemon::create(); SetNoClean(1); nohtml = ([ "BR": "", "P" : "", "/P" : "", "HREF" : "", ">" : "", ! "NAME" : "", "/A" : "", "I" : "", "/I" : "", "PRE" : "", ! "/PRE" : "", "STRONG" : "", "/STRONG" : "", "TABLE" : "", ! "/TABLE" : "", "TR" : "", "/TR" : "", "TD" : "", "/TD" : ""]); term_info = ([ ]); term_info["unknown"] = ! ([ "RESET": "", "BOLD": "", "FLASH":"", "BLACK":"", "RED":"", ! "BLUE":"", "CYAN":"", "MAGENTA":"", "ORANGE":"", "YELLOW":"", ! "GREEN":"", "WHITE":"", "BLACK":"", "B_RED":"", "B_ORANGE":"", ! "B_YELLOW":"", "B_BLACK":"", "B_CYAN":"","B_WHITE":"", "B_GREEN":"", ! "B_MAGENTA":"", "STATUS":"", "WINDOW":"", "INITTERM": "", ! "ENDTERM":""]) + nohtml; term_info["ansi"] = ! ([ "RESET":ANSI("0"), "BOLD":ANSI(1), "FLASH":ANSI(5), ! "BLACK":ANSI(30), "RED":ANSI(31), "GREEN":ANSI(32), ! "ORANGE":ANSI(33), "YELLOW":ANSI(1)+ANSI(33), "BLUE": ANSI(34), ! "CYAN":ANSI(36), "MAGENTA":ANSI(35), "BLACK":ANSI(30), ! "WHITE": ANSI(37), "B_RED":ANSI(41), "B_GREEN":ANSI(42), ! "B_ORANGE":ANSI(43), "B_YELLOW":ANSI(1)+ANSI(43), "B_BLUE":ANSI(44), ! "B_CYAN":ANSI(46), "B_BLACK":ANSI(40), "B_WHITE": ANSI(47), ! "CLEARLINE":ESC("[L")+ESC("[G"), "B_MAGENTA":ANSI(45), "STATUS":"", ! "WINDOW":"", "INITTERM":ESC("[H")+ESC("[2J"), "ENDTERM":"" ]) + ! nohtml; term_info["freedom"] = ! ([ "RESET": ESC("G0"), "BOLD":ESC("G@"), "FLASH":ESC("G2"), ! "BLACK":"", "RED":"", "GREEN":"", "ORANGE":"", "YELLOW":"", "BLUE":"", ! "CYAN":"", "MAGENTA":"", "BLACK":"", "WHITE":"", "B_RED":ESC("GD"), ! "B_GREEN": ESC("GD"), "B_ORANGE":ESC("G4"), "B_YELLOW":ESC("G4"), ! "B_BLUE":ESC("G4"), "B_CYAN":ESC("GD"), "B_BLACK": ESC("GD"), ! "B_WHITE":ESC("G4"), "B_MAGENTA":("G4"), "STATUS":"", "WINDOW":"", ! "CLEARLINE":"\r", "INITTERM":"", "ENDTERM":"" ]) + nohtml; term_info["ansi-status"] = ! ([ "RESET": ANSI("0;37;40"), "BOLD":ANSI(1), "FLASH":ANSI(5), ! "BLACK":ANSI(30), "RED":ANSI(31), "GREEN":ANSI(32), "ORANGE":ANSI(33), ! "YELLOW":ANSI(33), "BLUE":ANSI(34), "CYAN": ANSI(36), ! "MAGENTA": ANSI(35), "BLACK":ANSI(30), "WHITE":ANSI(37), ! "B_RED":ANSI(41), "B_GREEN":ANSI(42), "B_ORANGE":ANSI(43), ! "B_YELLOW": ANSI(1)+ANSI(43), "B_BLUE":ANSI(44), ! "B_CYAN": ANSI(46), "B_BLACK":ANSI(40), "B_WHITE":ANSI(47), ! "B_MAGENTA":ANSI(45), "STATUS":ESC("[23;24r")+ESC(8), ! "WINDOW":ESC(7)+ESC("[0;22r")+ESC("[22H\n"), ! "INITTERM":ESC("[H")+ESC("[J")+ESC("[23;24r")+ESC("23H\n"), ! "CLEARLINE":"\r", "ENDTERM":ESC("[0r")+ESC("[H")+ESC("[J") ]) +nohtml; ! term_info["xterm"] = ! ([ "RESET" : ANSI("0;37;40"), "BOLD": ESC("[7m"), ! "FLASH":ESC("[5m$<2>"), "BLACK":ANSI(30), "RED":ANSI(31), ! "GREEN":ANSI(32), "ORANGE":ANSI(33), "YELLOW":ANSI(33), ! "BLUE":ANSI(34), "CYAN":ANSI(36), "MAGENTA":ANSI(35),"BLACK":ANSI(34), ! "WHITE":ANSI(38), "B_RED":ANSI(41), "B_GREEN":ANSI(42), ! "B_ORANGE":ANSI(43), "B_YELLOW":ANSI(43), "B_BLUE":ANSI(44), ! "B_CYAN":ANSI(46), "B_BLACK":ANSI(40), "B_WHITE": ANSI(47), ! "B_MAGENTA": ANSI(45), "STATUS":"", "WINDOW":"", "INITTERM":"", ! "CLEARLINE":"\r", "ENDTERM":"" ]) + nohtml; ! term_info["html"] = term_info["unknown"] + ! ([ "RED" : "<FONT COLOR=\"#FF0000\">", ! "GREEN" : "<FONT COLOR=\"#00FF00\">", ! "BLUE" : "<FONT COLOR=\"#0000FF\">", ! "YELLOW" : "<FONT COLOR=\"#FFFF00\">", ! "CYAN" : "<FONT COLOR=\"#00A0DD\">", ! "MAGENTA" : "<FONT COLOR=\"#C50067\">", ! "YELLOW" : "<FONT COLOR=\"#FFFF00\">", ! "RESET": "</FONT>", ! "BR" : "<BR>", "P" : "<P>", "/P" : "</P>", ">" : ">", ! "HREF" : "<A HREF=", "NAME" : "<A NAME=", "/A" : "</A>", ! "I" : "<I>", "/I" : "</I>", "PRE" : "</PRE>", "/PRE" : "</PRE>", ! "STRONG" : "<STRONG>", "/STRONG" : "</STRONG>", ! "TABLE" : "<TABLE>", "/TABLE" : "</TABLE>", "TR" : "<TR>", ! "/TR" : "</TR>", "TD" : "<TD>" , "/TD" : "</TD>" ]); } mapping query_term_info(string type) { *************** *** 108,114 **** string GetHTML(string str) { int i, tot, fcount = 0, ncount = 0; string tmp; ! str = terminal_colour(str, term_info["html"]); tmp = str; while( (i = strsrch(tmp, "<FONT")) != -1 ) { --- 108,114 ---- string GetHTML(string str) { int i, tot, fcount = 0, ncount = 0; string tmp; ! str = terminal_colour(str, term_info["html"]); tmp = str; while( (i = strsrch(tmp, "<FONT")) != -1 ) { diff -c -r --new-file ds1.1/lib/daemon/time.c ds2.1/lib/daemon/time.c *** ds1.1/lib/daemon/time.c Sun Feb 1 21:30:03 1998 --- ds2.1/lib/daemon/time.c Wed Jul 5 00:00:58 2006 *************** *** 21,32 **** daemon::create(); Zones = ([]); ! tmp = localtime(time()); LocalZone = tmp[LT_ZONE]; x = tmp[LT_GMTOFF] / 3600; if( file_size(CFG_TIME) < 1 ) return; i = sizeof(lines = filter(explode(read_file(CFG_TIME), "\n"), ! (: $1 && $1 != "" && $1[0] != '#' :))); while(i--) { string *words; --- 21,32 ---- daemon::create(); Zones = ([]); ! tmp = local_time(time()); LocalZone = tmp[LT_ZONE]; x = tmp[LT_GMTOFF] / 3600; if( file_size(CFG_TIME) < 1 ) return; i = sizeof(lines = filter(explode(read_file(CFG_TIME), "\n"), ! (: $1 && $1 != "" && $1[0] != '#' :))); while(i--) { string *words; diff -c -r --new-file ds1.1/lib/daemon/tmp/ACID.c ds2.1/lib/daemon/tmp/ACID.c *** ds1.1/lib/daemon/tmp/ACID.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/ACID.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return ACID; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/ALL_DAMAGE.c ds2.1/lib/daemon/tmp/ALL_DAMAGE.c *** ds1.1/lib/daemon/tmp/ALL_DAMAGE.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/ALL_DAMAGE.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return ALL_DAMAGE; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_AMULET.c ds2.1/lib/daemon/tmp/A_AMULET.c *** ds1.1/lib/daemon/tmp/A_AMULET.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_AMULET.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_AMULET; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_ARMOUR.c ds2.1/lib/daemon/tmp/A_ARMOUR.c *** ds1.1/lib/daemon/tmp/A_ARMOUR.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_ARMOUR.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_ARMOUR; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_BELT.c ds2.1/lib/daemon/tmp/A_BELT.c *** ds1.1/lib/daemon/tmp/A_BELT.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_BELT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_BELT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_BODY_ARMOUR.c ds2.1/lib/daemon/tmp/A_BODY_ARMOUR.c *** ds1.1/lib/daemon/tmp/A_BODY_ARMOUR.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/A_BODY_ARMOUR.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_BODY_ARMOUR; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_BOOT.c ds2.1/lib/daemon/tmp/A_BOOT.c *** ds1.1/lib/daemon/tmp/A_BOOT.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/tmp/A_BOOT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_BOOT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_CLOAK.c ds2.1/lib/daemon/tmp/A_CLOAK.c *** ds1.1/lib/daemon/tmp/A_CLOAK.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_CLOAK.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_CLOAK; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_GLOVE.c ds2.1/lib/daemon/tmp/A_GLOVE.c *** ds1.1/lib/daemon/tmp/A_GLOVE.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/tmp/A_GLOVE.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_GLOVE; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_HELMET.c ds2.1/lib/daemon/tmp/A_HELMET.c *** ds1.1/lib/daemon/tmp/A_HELMET.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_HELMET.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_HELMET; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_LONG_BOOT.c ds2.1/lib/daemon/tmp/A_LONG_BOOT.c *** ds1.1/lib/daemon/tmp/A_LONG_BOOT.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/tmp/A_LONG_BOOT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_LONG_BOOT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_LONG_GLOVE.c ds2.1/lib/daemon/tmp/A_LONG_GLOVE.c *** ds1.1/lib/daemon/tmp/A_LONG_GLOVE.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/tmp/A_LONG_GLOVE.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_LONG_GLOVE; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_LONG_SOCK.c ds2.1/lib/daemon/tmp/A_LONG_SOCK.c *** ds1.1/lib/daemon/tmp/A_LONG_SOCK.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_LONG_SOCK.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_LONG_SOCK; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_MAX_ARMOUR_BIT.c ds2.1/lib/daemon/tmp/A_MAX_ARMOUR_BIT.c *** ds1.1/lib/daemon/tmp/A_MAX_ARMOUR_BIT.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/A_MAX_ARMOUR_BIT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_MAX_ARMOUR_BIT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_PANTS.c ds2.1/lib/daemon/tmp/A_PANTS.c *** ds1.1/lib/daemon/tmp/A_PANTS.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_PANTS.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_PANTS; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_RING.c ds2.1/lib/daemon/tmp/A_RING.c *** ds1.1/lib/daemon/tmp/A_RING.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/tmp/A_RING.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_RING; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_SHIELD.c ds2.1/lib/daemon/tmp/A_SHIELD.c *** ds1.1/lib/daemon/tmp/A_SHIELD.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_SHIELD.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_SHIELD; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_SHIRT.c ds2.1/lib/daemon/tmp/A_SHIRT.c *** ds1.1/lib/daemon/tmp/A_SHIRT.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_SHIRT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_SHIRT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_SOCK.c ds2.1/lib/daemon/tmp/A_SOCK.c *** ds1.1/lib/daemon/tmp/A_SOCK.c Sun Feb 1 21:29:54 1998 --- ds2.1/lib/daemon/tmp/A_SOCK.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_SOCK; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_VEST.c ds2.1/lib/daemon/tmp/A_VEST.c *** ds1.1/lib/daemon/tmp/A_VEST.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_VEST.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_VEST; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_VISOR.c ds2.1/lib/daemon/tmp/A_VISOR.c *** ds1.1/lib/daemon/tmp/A_VISOR.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_VISOR.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_VISOR; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_WEAPON.c ds2.1/lib/daemon/tmp/A_WEAPON.c *** ds1.1/lib/daemon/tmp/A_WEAPON.c Sun Feb 1 21:29:55 1998 --- ds2.1/lib/daemon/tmp/A_WEAPON.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_WEAPON; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/A_WEARON.c ds2.1/lib/daemon/tmp/A_WEARON.c *** ds1.1/lib/daemon/tmp/A_WEARON.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/A_WEARON.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <armour_types.h> - int armour() { return A_WEARON; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/BLADE.c ds2.1/lib/daemon/tmp/BLADE.c *** ds1.1/lib/daemon/tmp/BLADE.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/BLADE.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return BLADE; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/BLUNT.c ds2.1/lib/daemon/tmp/BLUNT.c *** ds1.1/lib/daemon/tmp/BLUNT.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/BLUNT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return BLUNT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/COLD.c ds2.1/lib/daemon/tmp/COLD.c *** ds1.1/lib/daemon/tmp/COLD.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/COLD.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return COLD; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/GAS.c ds2.1/lib/daemon/tmp/GAS.c *** ds1.1/lib/daemon/tmp/GAS.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/GAS.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return GAS; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/HEAT.c ds2.1/lib/daemon/tmp/HEAT.c *** ds1.1/lib/daemon/tmp/HEAT.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/HEAT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return HEAT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/KNIFE.c ds2.1/lib/daemon/tmp/KNIFE.c *** ds1.1/lib/daemon/tmp/KNIFE.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/KNIFE.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return KNIFE; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/MAGIC.c ds2.1/lib/daemon/tmp/MAGIC.c *** ds1.1/lib/daemon/tmp/MAGIC.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/MAGIC.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return MAGIC; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/MAX_DAMAGE_BIT.c ds2.1/lib/daemon/tmp/MAX_DAMAGE_BIT.c *** ds1.1/lib/daemon/tmp/MAX_DAMAGE_BIT.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/MAX_DAMAGE_BIT.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return MAX_DAMAGE_BIT; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/SHOCK.c ds2.1/lib/daemon/tmp/SHOCK.c *** ds1.1/lib/daemon/tmp/SHOCK.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/SHOCK.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return SHOCK; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/tmp/WATER.c ds2.1/lib/daemon/tmp/WATER.c *** ds1.1/lib/daemon/tmp/WATER.c Sun Feb 1 21:29:56 1998 --- ds2.1/lib/daemon/tmp/WATER.c Wed Dec 31 19:00:00 1969 *************** *** 1,2 **** - #include <damage_types.h> - int damage() { return WATER; } --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/underworld.c ds2.1/lib/daemon/underworld.c *** ds1.1/lib/daemon/underworld.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/underworld.c Wed Dec 31 19:00:00 1969 *************** *** 1,111 **** - /* /daemon/underworld.c - * From Dead Souls LPMud - * This object belongs to Dead Souls LPMud and is NOT part of - * the Dead Souls LPC Library distribution - * Any use of this object or the code contained within - * outside of Dead Souls LPMud without the express written - * permission of the Dead Souls LPMud administration is prohibted - * copyright (c) 1995 Dead Souls LPMud - * created by Descartes of Borg 950402 - * Version: @(#) underworld.c 1.5@(#) - * Last modified: 96/10/27 - */ - - #ifdef Dead SoulsLPMud - - #include <lib.h> - #include <dirs.h> - #include <rooms.h> - - inherit LIB_DAEMON; - - string array UndeadTypes = ({ "ghost", "phantom", "vampire", "shade", - "wraith", "zombie", "mummy", "skeleton", - "ghoul", "werewolf", "liche" }); - - static void create() { - daemon::create(); - SetNoClean(1); - } - - int CanFly(string type) { - switch(type) { - case "ghost": case "phantom": case "vampire": case "shade": - case "wraith": - return 2; - - default: - return 0; - } - } - - int GetMaterial(string type) { - switch(type) { - case "ghost": case "phantom": case "shade": case "wraith": - return 0; - - case "vampire": case "zombie": case "mummy": case "skeleton": - case "liche": case "ghoul": - return 1; - - default: - return 1; - } - } - - int isUndeadType(string type) { - return (member_array(type, UndeadTypes) != -1); - } - - string GetRandomUndead(object who) { - int x; - - if( who->ClassMember("mage") ) { - x = 10; - } - else { - x = 9; - } - switch(random(x)) { - case 0: - return "ghost"; - - case 1: - return "zombie"; - - case 2: - return "vampire"; - - case 3: - return "ghoul"; - - case 4: - return "skeleton"; - - case 5: - return "mummy"; - - case 6: - return "phantom"; - - case 7: - return "shade"; - - case 8: - return "wraith"; - - case 9: - return "liche"; - } - } - - string GetStandardRoom() { - return ROOM_START; - } - - string GetUnderworldRoom() { - return ROOM_START; - return DIR_UNDERWORLD_DOMAIN "/start"; - } - - #endif // Dead SoulsLPMud --- 0 ---- diff -c -r --new-file ds1.1/lib/daemon/unique.c ds2.1/lib/daemon/unique.c *** ds1.1/lib/daemon/unique.c Sun Feb 1 21:29:59 1998 --- ds2.1/lib/daemon/unique.c Wed Jul 5 00:00:58 2006 *************** *** 15,21 **** daemon::create(); Objects = ([]); if( file_size(SAVE_UNIQUE __SAVE_EXTENSION__) > 0 ) ! unguarded( (: restore_object, SAVE_UNIQUE :) ); } void eventTouchObject() { --- 15,21 ---- daemon::create(); Objects = ([]); if( file_size(SAVE_UNIQUE __SAVE_EXTENSION__) > 0 ) ! unguarded( (: restore_object, SAVE_UNIQUE :) ); } void eventTouchObject() { *************** *** 44,46 **** --- 44,55 ---- unguarded( (: save_object, SAVE_UNIQUE :) ); return ob; } + + mapping GetUniques(){ + return copy(Objects); + } + + mapping ResetUniques(){ + Objects = ([]); + unguarded( (: save_object, SAVE_UNIQUE :) ); + } diff -c -r --new-file ds1.1/lib/daemon/verbs.c ds2.1/lib/daemon/verbs.c *** ds1.1/lib/daemon/verbs.c Sun Feb 1 21:29:57 1998 --- ds2.1/lib/daemon/verbs.c Sun Jul 9 19:04:26 2006 *************** *** 1,5 **** /* /daemon/verbs.c ! * from the Dead Soulsr2 Object Library * handles the loading and rehashing of verbs * created by Descartes of Borg 951016 */ --- 1,5 ---- /* /daemon/verbs.c ! * from the Dead Souls Object Library * handles the loading and rehashing of verbs * created by Descartes of Borg 951016 */ *************** *** 14,19 **** --- 14,20 ---- static void create() { daemon::create(); Verbs = ([]); + SetNoClean(1); eventReloadVerbs(); } *************** *** 32,42 **** if( this_player() && cwd = (string)this_player()->query_cwd() ) { tmp = absolute_path(cwd, val); if( file_exists(tmp + ".c") && GetValidVerb(tmp) ) ! verbs = ({ tmp }); } if( !verbs ) { if( file_size(tmp) == -2 && GetValidVerb(tmp) ) ! verbs = map(get_dir(tmp+"/*.c"), (: $(tmp) + "/" + $1 :)); } else { string dir; --- 33,43 ---- if( this_player() && cwd = (string)this_player()->query_cwd() ) { tmp = absolute_path(cwd, val); if( file_exists(tmp + ".c") && GetValidVerb(tmp) ) ! verbs = ({ tmp }); } if( !verbs ) { if( file_size(tmp) == -2 && GetValidVerb(tmp) ) ! verbs = map(get_dir(tmp+"/*.c"), (: $(tmp) + "/" + $1 :)); } else { string dir; *************** *** 49,54 **** --- 50,63 ---- break; } } + foreach(dir in get_dir(DIR_SECURE_VERBS + "/")) { + dir = DIR_SECURE_VERBS + "/" + dir; + if( file_size(dir) != -2 ) continue; + if( file_exists( dir + "/" + val + ".c") ) { + verbs = ({ dir + "/" + val }); + break; + } + } if( !verbs ) return; } } *************** *** 60,82 **** foreach(dir in get_dir(DIR_VERBS + "/")) { dir = DIR_VERBS + "/" + dir; if( file_size(dir) == -2 ) ! verbs += map(get_dir(dir + "/*.c"), (: $(dir) + "/" + $1 :)); } } i = 0; foreach(verb in verbs) { object ob; string *verb_list; ! if( ob = find_object(verb) ) ob->eventDestruct(); if( ob = load_object(verb) ) { i++; if( !(verb_list = (string *)ob->GetVerbs()) ) ! verb_list = ({ explode(verb, "/")[<1][0..<3] }); else { verb_list += (string *)ob->GetSynonyms(); verb_list =distinct_array(map(verb_list, ! (: explode($1," ")[0] :))); } Verbs += expand_keys(([ verb_list : verb ])); } --- 69,96 ---- foreach(dir in get_dir(DIR_VERBS + "/")) { dir = DIR_VERBS + "/" + dir; if( file_size(dir) == -2 ) ! verbs += map(get_dir(dir + "/*.c"), (: $(dir) + "/" + $1 :)); ! } ! foreach(dir in get_dir(DIR_SECURE_VERBS + "/")) { ! dir = DIR_SECURE_VERBS + "/" + dir; ! if( file_size(dir) == -2 ) ! verbs += map(get_dir(dir + "/*.c"), (: $(dir) + "/" + $1 :)); } } i = 0; foreach(verb in verbs) { object ob; string *verb_list; ! if( ob = find_object(verb) ) ob->eventDestruct(); if( ob = load_object(verb) ) { i++; if( !(verb_list = (string *)ob->GetVerbs()) ) ! verb_list = ({ explode(verb, "/")[<1][0..<3] }); else { verb_list += (string *)ob->GetSynonyms(); verb_list =distinct_array(map(verb_list, ! (: explode($1," ")[0] :))); } Verbs += expand_keys(([ verb_list : verb ])); } *************** *** 90,96 **** } int GetValidVerb(string verb) { ! return !strsrch(verb, DIR_VERBS); } mapping GetVerbs() { return copy(Verbs); } --- 104,111 ---- } int GetValidVerb(string verb) { ! if(!strsrch(verb, DIR_VERBS) || !strsrch(verb, DIR_VERBS)) return 1; ! else return 0; } mapping GetVerbs() { return copy(Verbs); } diff -c -r --new-file ds1.1/lib/daemon/war.c ds2.1/lib/daemon/war.c *** ds1.1/lib/daemon/war.c Sun Feb 1 21:30:00 1998 --- ds2.1/lib/daemon/war.c Wed Dec 31 19:00:00 1969 *************** *** 1,86 **** - /* /daemon/war.c - * From Dead Souls LPMud - * A daemon to manage who can kill whom - * Created by Descartes of Borg 961117 - * Version: %A% - * Last modified: %D% - */ - - #include <lib.h> - - inherit LIB_DAEMON; - - private int LastWar = 0; - private class war War = 0; - - static void create() { - daemon::create(); - SetNoClean(1); - } - - varargs int GetAtWar(object agent, object target) { - string name; - - if( !War ) { - return 0; - } - if( !agent ) { - return 1; - } - name = agent->GetKeyName(); - if( member_array(name, War->aggressor->members) == -1 ) { - if( member_array(name, War->enemy->members) == -1 ) { - return 0; - } - } - if( !target ) { - return 1; - } - name = target->GetKeyName(); - if( member_array(name, War->aggressor->members) == -1 ) { - if( member_array(name, War->enemy->members) == -1 ) { - return 0; - } - } - return 1; - } - - mixed eventDeclareWar(object who, string victim, string reason) { - if( GetAtWar() ) { - return "There is already a war raging between " + - item_list(map(GetEnemies(), (: capitalize :))) + "."; - } - if( !leaderp(who) ) { - return "You do not have the power to declare war."; - } - if( time() - WAR_INTERVAL < LastWar ) { - return "Let the dust settle from the last war!"; - } - obs = filter(users(), function(object ob, string victim) { - if( !leaderp(ob) ) { - return 0; - } - return ob->ClassMember(victim); - }, victim); - obs -= ({ who }); - if( !sizeof(obs) ) { - return "The enemy must have a leader online for a declaration of war."; - } - War = new(class war); - War->start = time(); - War->reason = reason; - War->aggressor = new(class team); - War->aggressor->name = who->GetClass(); // multi-class??? - War->aggressor->leader = who->GetKeyName(); - War->aggressor->points = 0; - War->aggressor->war_chest = 0; - War->aggressor->members = ({ who->GetKeyName() }); - War->enemy = new(class team); - War->enemy->name = victim; - War->enemy->leader = enemy->GetKeyName(); - War->enemy->points = 0; - War->enemy->war_chest = 0; - War->enemy->members = ({ enemy->GetKeyName() }); - users()->eventPrint("%^BOLD%^GREEN%^" + who->GetCapName() + - " has declared war on " + pluralize(victim) + "!"); - } --- 0 ---- diff -c -r --new-file ds1.1/lib/doc/BASICS ds2.1/lib/doc/BASICS *** ds1.1/lib/doc/BASICS Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/BASICS Wed Jul 5 00:00:58 2006 *************** *** 0 **** --- 1,56 ---- + Handling Files: the Basics + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 1) The "more" prompt: + Text generally scrolls with the "more" system, which + reads a page, then prompts you to read further. In Frontiers, + the way to advance to the next page is to hit <return>. + This will take you to the next page of text. To + scroll backward, hit the "b" key, then <return>. + To stop reading the file, + hit the "q" key, and return. + + 2) The file/directory structure: + Information is stored in files. Files are organized in + directories. Directories are organized in other directories. + This text, for example, is in the file + /doc/BASICS + If you wanted to look at this file without the manual, you + could type: more /doc/BASICS + and you would get to read this file again. + + 3) Handling files and directories: + The /domains directory contains a bunch of other directories + which contain more directories and files. This way of organizing + information helps keep similar or related information together. + To look at the contents of the /domains directory, you type: + cd /domains + and then type: + ls + The "ls" command lets you see a list of the contents of the + directory you've specified. To go to your home directory, issue + the "cd" command by itself, then "ls". You will then see the + contents of your own directory. The top level directory of the + mud is accessed through "cd /" without quotations. If you "ls" + then, you'll see the directories in which *everything* in the + mud is kept. You may explore from there. + + 4) Common file/directory commands: + + ls - Lists your current working directory + cd - Changes directory to whatever you specify. If there is + a directory called joe in your current working directory, + "cd joe" without quotations will change your current + working directory to joe, and "ls" will list the contents + of that directory. + cd .. - Moves you up one directory. + more - Displays the contents of a file. Doesn't work with + directories. If schmoe is a file in your current working + directory, then "more schmoe" will display the contents + of that file. If it's a directory, you'll need to "ls". + ed - Lets you edit the specified file, if it belongs to you. + If in your home directory there is a file called + workroom.c, then "ed workroom.c" will allow you to edit + that file and change it to what you want. Read Chapter + 2 of this manual section for details on the editor. + + diff -c -r --new-file ds1.1/lib/doc/CHANGES ds2.1/lib/doc/CHANGES *** ds1.1/lib/doc/CHANGES Wed Mar 10 22:17:28 1999 --- ds2.1/lib/doc/CHANGES Wed Dec 31 19:00:00 1969 *************** *** 1,30 **** - ---- Version 1.1pre released ---- - 7 added Dvarsks improved Virtual Libs. Who knows we may provide - examples in the next revision. - 6 added ftpd support within the mud. This is courtesy of Dvarsk and - Lima. You must read and comply to the Lima USAGE document. - After you read that document you can start the ftpd using - something like - call /secure/daemon/inet->AddService("ftp", PORT_FTP, - "/secure/lib/net/ftp.c", DATAGRAM) if my feable memory is working. - 5 added /lib/std/story.c (read the lib to find out how to use it) - 4 lib/comp/container GetRadientLight() to GetRadientLight(ambient) - 3 mkdir 0-9 in $MUDHOME/lib/secure/save/postal - 2 in /lib/living.c remove arguments to direct_smell_obj() line 128 - 129 - 1 in /secure/daemon/master.c edit the lines 194-204 to be: - if( (tmp = base_name(ob)) == LIB_PLAYER || tmp == LIB_CREATOR) { - if( !PlayerName ) i = sizeof(stack = ({ob})+previous_object(-1)); - else if( file == DIR_PLAYERS+"/"+PlayerName[0..0]+"/"+ - PlayerName + __SAVE_EXTENSION__ ) - return 1; - else if( file == DIR_CRES+"/"+PlayerName[0..0]+"/"+ - PlayerName + __SAVE_EXTENSION__ ) - return 1; - else i = sizeof(stack = ({ ob })); - } - else if( tmp + __SAVE_EXTENSION__ == file ) return 1; - - ---- Version 1.0 released ---- - This was the orriginal - unversioned version. --- 0 ---- diff -c -r --new-file ds1.1/lib/doc/CREDITS ds2.1/lib/doc/CREDITS *** ds1.1/lib/doc/CREDITS Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/CREDITS Wed Jul 12 20:17:44 2006 *************** *** 0 **** --- 1,33 ---- + I'd like to thank the following people for their help, witting or + otherwise, in making the new release of Dead Souls possible: + + Sine qua non: Descartes, the legion of MudOS developers, and + all those coders who toiled at Nightmare, and Lars Pensjö. + Marius for his kind permission to bundle MudOS. + + Direct conributors: Haderach and his clever code and inspiration, Duuk + and his willingness to let me poke through his lib and + filch code. Great thanks to Marajin for his direct and + substantial contribution to the Windows port. + Much gratitude to Saquivor, for whom a town street is + now named, for getting the Windows socket code working. + Thanks also to the following for code donation, + support, and/or contribution: Tim@TimMUD, Manchi, + Brodbane, Ashon, Shadyman, Jonez, Cecil, Daelas. + + Appreciation of: Jayren, Kaylus, Arianrhod, Nosmo, Pyro, Abby, Balmung, + Aten, Metiscus, Garfield, Javelin, Alensin, Daelas, Root, + Kristus, Zeus, Dastuun, Detah, and Nulvect for their + thoughtful comments and suggestions. + + * Thanks to Frostmud.com for letting me test on their box. + * Thanks to Wolfpaw.com for letting me test on their box. + + + Much gratitude to playtesters: Karri, Aten, Tacitus, Kaatil, Atomic, Daelas. + + Also: Xyzzy He Is Cool + + Cratylus @ Dead Souls + July 2006 + diff -c -r --new-file ds1.1/lib/doc/README ds2.1/lib/doc/README *** ds1.1/lib/doc/README Sun Feb 1 21:45:26 1998 --- ds2.1/lib/doc/README Wed Dec 31 19:00:00 1969 *************** *** 1,22 **** - The Dead Souls Mud Library - Released 1 February 1998 - - The Dead Souls Mud Library is a special compilation of files from the - old Nightmare Mudlib that have been released into the public domain. - This code is provided as-is without any offering of support or - guarantees of suitability for any specific use. The existence of this - code in the public domain pertains only to the code in this - distribution. It does not imply or suggest permission to use other - code by the authors of this work or related works by other authors. - - This code is known to work with MudOS v22b25. You should download and - install whatever version of MudOS you desire. Be warned, however, - that newer versions may or may not work with this release. You may - have to modify the code in this distribution to get things to work. - Do not, under any circumstances, email the author of this distribution - for support. Your email will be deleted unread. If you have - questions, subscribe to the nightmare-mudlib mailing list by visiting - http://list.imaginary.com/mailman/listinfo/nightmare-mudlib. - - George Reese - 1 February 1997 --- 0 ---- diff -c -r --new-file ds1.1/lib/doc/RELEASE_NOTES ds2.1/lib/doc/RELEASE_NOTES *** ds1.1/lib/doc/RELEASE_NOTES Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/RELEASE_NOTES Wed Jul 12 13:29:17 2006 *************** *** 0 **** --- 1,621 ---- + ---- 2.1 --- + - Fixed relative include problem in QCS. + - Fixed memcheck. + - Added vis and invis to list of customizable messages with the + message command. + - Fixed bug in ls command with the -b flag. + - Fixed index problems in chat.c with class channels. + - Fixed a problem when looking at dummy items (e.g. buttons and doors). + - Fixed color code problem in the arch room screen. + - Fixed problem in look verb that caused problems looking at + objects that inherit LIB_DUMMY. Tons of thanks to Daelas for this save. + - Unused debug lines removed, general cleanup of ugly + or unnecessary comments. + - Miscellaneous tightening up of domain objects such as lowering + the max health of newts, etc. + - Miscellaneous tidying up of lib logic, such as preventing the + fly command to commence flight whether already flying or not. + - KNOWN ISSUES: + o The blackjack table is officially on the "I'm not fixing it" list. + It is left as an example of game code, but you are warned that + it contains some subtle and not-so-subtle errors in its calculations. + o addr_server.exe win32 binary removed, due to bugginess. Since + it hasn't been working for a while, and it was only noticed by + a bugtester, it's going away until post-2.1 + o A peculiarity in grammar with multiple corpses can be seen. This is + partly due to a MudOS idiosyncracy which will be addressed in the future. + o In some cases combat events appear slighly out of order. This + will be addressed in a rewrite of combat objects in the future. + + ---- 2.0r29 --- + - Fixed finger daemon to not display ip addresses to players. + - The verb copy now handles relative paths more gracefully. + - LIB_TEACHER can now know all languages with SetAllLanguages(1) + - Standard chairs and beds can no longer be taken when someone is using them. + - Fixed church elevator buttons. + - Fixed problem with "look at pile". + - Fixed problem with examining objects on surfaces. + - It is now also possible to look at things carried by others, + e.g. "look at shirt on fighter". + - Remote finger no longer betrays invisible people. + - Added sefun: alpha_strip + - Room descriptions now indicate which piece of furniture a creature + is resting on, if applicable. + - Objects on surfaces than can be sat or lain in are not visible + or accessible if someone is lying or sitting on that surface. e.g., + you can't examine or get the glasses under your butt on the chair. + - SetMaxHealthPoints now works as one would expect. The kitchen rat + is invincible no more. + - Look at <container> problem fixed. + - Bank tellers (Zoe) now do a better job of retaining the correct + surcharge on currency withdrawals. + - Added /secure/obj/glasses.c as a creation object. Since you wear them, + it's hard to lose them accidentally. Since few things are called "glasses", + they won't get in the way of creating objects. New creators will have them + automatically added to the table in their sample room. + - One may now have a smiley in front of a channel message without + it turning into an emote. + - Fixed a conflict in the parsing system. + - Verbified "force". + - Fixed vendor bugs: appraising at zero, confusion with similar items. + - Beefed up the answers_to sefun, to handle adjectives. + - Fixed a couple of bugs in the lead/follow system. + - Fixed null error when selling to non-vendors. + - Fixed a channel log bug that logged to one of two files for + some channels, depending on whether someone was logged on (!!). + - Fixed bug in meals that prevented empty bottles replacing + full ones. + - Fixed a bug in the MudOS parser that screwed up things with apostrophes. + + ---- 2.0r28 --- + - Fixed minor bug in body.c that interfered with collapsing. + - Fixed message boards. + - Added command: snoopreport + - Fixed bug that caused players to be essentially immortal. + - Player death history is now accurately recorded. + - The command mudlist now ignores colors. + + ---- 2.0r27 --- + - Fixed currency problem in dying NPC's. + - Added commands: env, polyglottize + - Fixed "about" verb. + - Tweaked snoop daemon and snoop objects. + - Added pay-for-lessons feature in language teachers. + - Fixed bug in LIB_EXITS that hosed various things, + including wandering NPC's. + - mv command no longer overwrites an existing destination file. + - Fixed campus rooms with hosed CanReceive()'s that horked logins. + - Turned "move" command into "transfer", to address a conflict with + the "move" verb. - Fixed bug in admintool that prevented assistant admins from + using it. + - Fixed bug in eval that prevented assistant admins from using it. + - i3router: dynamic channel data is now persistent (newly created + channels won't disappear when the router resets). + - i3router: fixed a bug in chanlist-reply that stopped the + channel list being sent to LPUni lib muds. + - Modified install process to handle compiling on Wolfpaw servers. + - Added code example domain that was donated by Daelas @ Moraelinost. + - Added new podium, conference room, and margins command that were + donated by Daelas @ Moraelinost. + - i3router: correct password is now honored. + - Fixed help daemon bug that displayed race help twice. + - QCS: creating an enter no longer wipes exits from an existing + target room. + - Fixed bug in rescue login (Thanks, Nulvect). + - Fixed bug in tell command that mishandled mud name ambiguity. + - Fixed bug in CHAT_D that failed to return remote channel listeners. + - i3router: fixed bug that incorrectly rejected targeted emotes. + - Killing a creature super-ultra-extremely fast no longer + generates multiple corpses. + - QCS: Fixed some money problems with both how much things cost and + how much money they have. + - Modified encumbrance to be rather less cumbersome. + - Mailer default behavior now is to notify you when you receive new + mail. Already created characters do not have this default. + - Fixed opacity problem in worn storage. + - Fixed message board in arch room. + + ---- 2.0r26 --- + - Plugged some serious security holes ( http://dead-souls.net/news.html#16jun06 ) + - Cleaned up some unnecessary call_outs in lib objects. + - Added LIB_PULL. + - Added Virtual Campus domain. + - Fixed qcs problem that screwed LIB_DUMMY. + - Fixed local channel emote problem in RESTRICTED_INTERMUD mode. + - Added sefun: alpha_crypt. + - Added conference room east of the Adventurer's Hall. + - admintool no longer lets you remove the last + currency. + - COMPAT BUSTER: UNIX version now uses MD5 crypt, like the Windows + version. Character files created prior to using this driver + will not work with this driver. + - rwho no longer cares if the issuer of the + command is invisible. + + ---- 2.0r25 --- + - r24 had some unfortunate licensing problems attached. + r25 includes a Win32 native binary that does not depend + on any GPL code to run. + - This release is hereby dedicated to Saquivor, who was + instrumental in getting this binary compiled. + - r25 lib does not differ from r24 or r23. Unless you + need the native Win32 binary, you should skip this + release if you have r23 or r24. + + ---- 2.0r24 --- + - Ran into some trouble when releasing r23. For + technical reasons, it's being re-released as r24. + + ---- 2.0r23 --- + - Fixed a bug that sent local channel data to the i3 + router. Sorry about this, guys. As soon as I found + this, I killed it. It appears to have affected r22 only. + - Fixed a conflict between room SetActions and LIB_FISHING. + - It is no longer possible to fish while asleep. + - Admins can no longer decre themselves. + - Modified MudOS source to compile on IRIX using Nekoware. + - Fixed PK bug. Added PLAYER_KILL to config.h . + - Fixed problem with monitor failures and runaway + snooper generation. + - Fixed gate command, renamed it stargate.c. + - Added Administrator's Guidebook. Initial draft available + at http://dead-souls.net/guide/ + - Added downloads.html to doc pages. + - Added verbs.html to doc pages. + - Added i3who command to list who data on all muds. + - Fixed a germ bug that triggered a combat message. + - Fixed an invalid index bug in STARGATE_D and + in LIB_STARGATE. + + ---- 2.0r22 --- + - Changed UNIX config and start scripts to assume + Bourne shell rather than bash. + - Fixed "look in" bug in transparent containers. + - Added stargate lab east of the Creators' Hall. + - Added sefun: compare_array. + - Fixed divide-by-zero bug in net worth calculator. + - Fixed "look in" bug in opaque containers. + - Fixed snoop and monitoring bugs. + - Added SetAction to rooms, for time-based events. See + /domains/town/room/shore.c for an example. + - Fixed plural limb problem in RACES_D help. + - Worn/wielded items must be removed/unwielded before they can be dropped with "drop all". + - Worn/wielded items must be removed/unwielded before they can be sold with "sell all". + - Consolidated Windows and UNIX distributions into a + single download file. + - Converted class variables in STARGATE_D to mappings, + and fixed "inbound/idle gate" bug, as well as room + message bug. + - Updated FAQs and miscellaneous documentation. + - Fixed bug in RESTRICTED_CHANNELS. + - Cleaned up odd function names in LIB_LEAD. + - Tightened up earmuffing, added muffing of entire muds. + - Fixed a bug in look verb that prevented looking + at dummy items. + - Fixed a few bugs in trainers. Added a SetNoSpells() lfun + to control whether a trainer automatically can teach the + spells she knows. + - Fixed noisy index error in LIB_GERM. + - Fixed CHAT_D bug that prevented talking on some channels. + - Fixed problem in LIB_FISHING that made one's catch disappear. + - Fixed opacity for containers. If an item's opacity is about + 33 or below, its contents are visible on casual examination. + Otherwise, you have to "look in" it. + + ---- 2.0r21 --- + - Fixed a bug in "following" code. + - Fixed a bug in trainer code. + - Fixed latent SNOOP_D bugs. + - Lowered log rotation threshold. + - Corrected stat distortion problem in races.o. + - Added the domaincreate command. + - General minor typo/bugfixes. + - Tidied up interaction between rid, suicide, and + PLAYERS_D. + - Updated FAQs. + - Fixed bug in scan when providing all of the flags: -e -d -i + - Fixed put.c. + - Fixed unusually generous vendors. + - Fixed bug in objects() sefun that interfered + with resets. + - Removed clan inheritance from gstaff.c. + + ---- 2.0r20 --- + - "put all in <thing>" now ignores worn and wielded + items. + - Added commands: switchrouter, domainadmin, + monitor, unmonitor. + - (hopefully) Fixed rare and peculiar bug that hosed + up logins unpredictably. + - Added the Jonez stargate system. + - Container bug fixed. It is now possible to put + amounts of money into containers and onto surfaces. + - Daemonized snoop system. This permits the logging + of snoop data, unmanned snoop logs, and snooping + multiple players at once. Still slightly buggy, so + please report any problems with it. + - The encre and decre of non-logged-on users now + behaves properly. + - Furnaces now destroy objects almost immediately. + - Fixed voting system. + - LIB_GUILD changed to LIB_CLAN. It works, but is + not actually useful. Proper clan functionality + is planned post-2.1. + - Heal command now fixes individual limbs as well. + - Added ENABLE_ENCUMBRANCE define to config.h to + toggle the encumbrance combat modifier. + - Modified combat so it's difficult to fight while + carrying stuff. Anything worn or wielded doesn't + affect combat capability. NPC's are unaffected by this. + - Fixed horrendous carry-capacity leak in all containers. + - Added "every" token to reload verb, enabling the + reload of all loaded objects that inherit the specified + library object, eg "reload every npc". + - Fixed bugs in invisibility. + - Enabled QCS to work in /domains directories for + creators set as domain admins with the + domainadmin command. + - Fixed error in RACES_D that dramatically distorted stats. + - Added sefun: domain_admin. + - Fixed mudlist cache problem. + - Added command: switchrouter, domainadmin. + - Added set_heart_beat to QCS. + - Fixed bugs in commands: banish, anglicize. + - Integrated most packet data with network room. + - Added router room for I3 router debugging. + - Integrated most I3 packets with router room. + + ---- 2.0r19 --- + - Fixed menu item bug in LIB_BARKEEP. + - Fixed Ylsrim pub. + - Added keepalive pinger tool to wiz chest. + - Added commands: anglicize, debug, expel, resetpasswd. + - Fixed first boot problem with /secure/daemon/letters.c. + - Driver: set heart_beat to approximately one per second. + - Driver: added locale workaround to startmud script. + - Added Brodbane's New and Improved cp command. + - Added Brodbane's sefuns: wild_card, remove_dots. + - Elision bug in pager.c fixed by Brodbane. + - Added network troubleshooting room. + - Fixed bug in invisibility. + - Made tricorder and remote control emit warnings, logs, + and errors when used by a non-creator who does not have a + visitor pass. + - Added colon emote behavior to channels, eg, "ds :smile" works + the same as "dsemote smile". + - Tim's I3 router integrated into the lib. Fixes forthcoming. + - Object Properties map variable now persists as well. + - Added Brodbane's dsversion command. + - Fixed bug in LIB_SENTIENT eventReceiveEmote. + - Added Shadyman's fix to the imc2 daemon. + - Added language teacher and schoolhouse to /domains/town. + - Added LIB_TEACHER. + - Tweaked interactive.c to omit null obvious exits. + - Fixed "list" conflict with restricted channels and shops. + - Added SetNativeLanguage to QCS. + - Added PINGING_MUDS, ENGLISH_ONLY and HUMANS_ONLY defines to config.h. + - Added commands: anglicize, debug, expel. + - Added SetNativeLanguage() to LIB_LANGUAGE. + - Added GetEquippedLimbs() to LIB_BODY. + - Visitor's pass now suppresses autosave messages. + - Full cardinal direction aliases added to players (eg "north"). + - Added direction aliases to 'peer' command. + - Player Properties map variable now persists across quits and boots. + This may or may not be a good thing, and could change in + future releases. + - Added sefuns debug(), tell_creators(); + - Fixed socket_address(). + - Added AUTOEXEC_D. + + ---- 2.0r18 --- + - Changed default intermud router to 149.152.218.102 port 23 + - Added a sanity check in telnet room. + - Fixed bug in Newbie Mansion Quest (thx Jonez). + - Added verb: pulsecheck. + - Fixed bug in delete verb that broke when deleting an + item with a relative include defined. + - Fixed a wielding bug that let you wield a two-handed + weapon AND a one-handed weapon. + - Added more damage types. + - Fixed month bug in timestamp.c. + - Fixed light bug in ROOM_VOID. + + ---- 2.0r17 --- + - Fixed bug that prevented assistant admins from shutting down. + - Added Shadyman's emote doc. + - Tweaked timestamp() (thx, Jonez). + - Tweaked "dest" code (thx, Cecil). + - Added convert_ascii() sefun to stringify ascii codes. + - Added get_random_living() sefun. + - QCS now sanely stops when the target is virtual. + - Players can no longer be hosed by being initfixed. + - Fixed bug that returned conflicting messages if + an intermud tell was received while invis with + voicemail enabled. + - timezone.cfg can now be set to blank with admintool. + - Fixed problem in CHAT_D that restricted local channel + emotes when intermud was set to be restricted. + - Fixed a bug in null currency addition in admintool. + - Smushed another apostrophe problem. This is really ridiculous, I + should just fix the real problem, but it's such a dumb + bug, it's easier to pretend it doesn't exist. + - Added SetCustomXP to /lib/combat so that NPC's can have + expee value independent of that calculated from their level. + - Added SetCustomXP to QCS. + - Wrapped users() efun in a sefun to exclude users without + an environment. + - Removed old, counterproductive intermud update event. + - Added log rotation daemon in /secure/daemon/log.c + - Added a log rotation check every 2 hours. + - Format of timestamp() sefun changed to prevent screwing the + mud when running on Windows and logs rotate. + - Fixed bug in update() sefun. + - Prettified devel mud welcome file and added warning about + submitted code being automatically GPL. + - The title and chfn commands now automatically update finger + info with current data. + - *COMPAT BUSTER* RACES_D re-written (Thanks, Ashon). If you've + added your own races, you'll need to re-add them using the new format. + - /www FAQ material updated. + - Fixed Radagast's training skills, fixed QCS trainer creation. + - Modified telnet room to not permit recursive logins on the + development Dead Souls mud. + - Removed nonexistent boards from boards command. + - Added commands: addraces, removeraces, ascii, resetall, flushobs. + + ---- 2.0r16 --- + - Admin email specified at login now gets sent to config.h. + - New FAQ material added to /www + - If a file exists in /doc/help/races for a specified race, + help <race> will display that file instead of the autogenerated + race body data. + + ---- 2.0r15 --- + - Intermud can be disabled entirely by toggling DISABLE_INTERMUD + in /secure/include/config.h. + - *COMPAT BUSTER* Basic framework for race-based skills in + place. Old races.o files will not work with the new race + data file format expected by RACES_D. + - Fleas and lice examples now unbroken. + - Peer command unbroken. + - Fixed miscellaneous i3 services bugs. + - Tweaked the apostrophe workaround. + - "cd here" now works. + - Added intermud link failure/restoration announcement + to arch room. + - Fixed LIB_READ so that receiving a string for a functional's + return of a GetRead makes that string the text to be read. + - Fixed read bug in /lib/bboard.c. + - Fixed a problem with eval that puked on ASSIST members. + - Fixes and updates made to answering machine. Intermud + tell support added. + - Intermud tells now reach the player if she is invisible. The + tell sender's mud receives an "unknown user" error, and the + player receives an "unknowingly tells you" message. + - Intermud channels can be disabled by toggling + RESTRICTED_INTERMUD in /secure/include/config.h. Exceptions + to this restriction can be made by adding users to + the INTERMUD group using admintool. + - Automatic promotion of new characters to creator status can + be enabled by editing /secure/include/config.h and + toggling AUTO_WIZ. + - Update and runtime errors now attempt to display more helpful + messages to the user, if the user is a creator (Thx, Brodbane). + - Error logs now include timestamps. + - Added trainers to QCS. + - *COMPAT BUSTER*: Trainer skills now have to be specified with + an array, not just a series of strings: + RIGHT: AddTrainingSkills( ({ "alpha", "bravo", "charlie" }) ); + WRONG: AddTrainingSkills( "alpha", "bravo", "charlie" ); + - Fixed error message bug in /lib/trainer.c. + - Fixed chat.c bug that allowed emotes from earmuffed players + to be printed. + - Added languages to say verb. + - Added languages to reading. + - Added commands: language, ping. + - Updated/added various help files. + - Added FAQs (/doc/faq...accessed with the faq command). + - Updated Player's Handbook. + - Miscellaneous header fixes. + - Fixed issues in description.c and look.c that interfered with + having multiple Item elements in objects and having arrays + for keys in Item elements in objects. + - Added IDLE_TIMEOUT to /secure/include/config.h + - Added sefuns: imud_privp, find_inheritors, find_deep_inheritors, + securep. + - Overhauled limb and corpse decay. DECAY_D now handles the + callouts, reducing the number of decaying callouts to 1, regardless + of the number of limbs and corpses lying about. + - Limb ID bug fixed. + - Added tweaks to read verb and faq command submitted by Manchi. + + ---- 2.0r14 --- + - Added barkeeps to QCS. + - Added vendors to QCS. + - Barkeeps now properly handle array keys in menu items. See Lars. + - Updated www directory. + - Abbreviated RELEASE_NOTES: dropped pre-v2 data. + - Added commands: consider, whomuffed. + - Fixed QCS bug that hosed room paths. See "room filenames" notes + in chapter 35 of the Creator's Manual. + - Fixed problem with hobbling 4-legged NPC's. + - Additional docs, helpfiles, updated faqs and expanded QCS chapters. + + ---- 2.0r13 --- + - Numerous minor fixes to commands and lib objects. + - Keepalive daemon implemented to detect when the intermud + connection is down and attempts to restart it. + - Intermud services now supports "auth" packets, somewhat. + - The bk command now also works on objects. + - Added commands: kills, chanban, chanunban, earmuff, unmuff. + - Fixed duplicate handbook bug in encre. + - New cres are no longer forced to quit. + - Fixed parser bug when dealing with identical items in different + containers. + - Added sefuns: query_names, answers_to, add_event, remove_event, + update, local_ctime. + - Fixed events system (see *_event sefuns). + - Non-admins now can't use the dest or trans commands on admins. Note that + if a creator really wants to, she could get around using the commands and + trans or dest you anyway. However, now they can't do it "accidentally". + - The bull shark is no longer drinkable. + - Applied workaround to an apostrophe bug. Full fix pending. + - More sefun documentation. + + ---- 2.0r12 --- + - Fixed function conflict that made "scan -i" fail. + - Tightened up "get" lib code. + - Verbified "zap". + - Added atoi sefun. + - Added LIB_WORN_STORAGE to more gracefully handle wearable containers + like backpacks and such, also added it to QCS. + - QCS: fixed a bug that hosed up armor protection settings. + + ---- 2.0r11 --- + - Added findobs sefun and findobj command. + - Fixed "no steal" item property so thieves can't steal such things. + - Android corpses and severed limbs now decay in their own special way. + - Fixed up the sample flu and cold so they don't permanently affect a + a player's stats. Added a very nasty rage virus. + - Ftpd and httpd now work (Thanks to Duuk @ Haven). To enable them, uncomment + inet in /secure/cfg/preload.cfg. They are UNSUPPORTED, and if they ruin + your life, it's not my problem. System security is on you. + - Added valid_link() to master.c so that link() efun works. An interactive, + privileged, nonforced object is required in the previous_object() stack + to avoid abuse. Do NOT use this functionality unless you know EXACTLY + what you're doing. It probably doesn't work the way you think it does. + Be especially careful not to link privileged files to directories that + unprivileged users have write access to. Windows users should just + forget they read any of this. + - Verbified dest command. Peculiar "desting of nonexistent things" bug + should be dead at long last. + - Golems can have their composition specified. As an example, the combat + dummy is now a wood golem. + - Creatures born without limbs are now able to fight while in their + natural prone position. Creatures who used to have limbs and no longer + do have more limited options. + - SetUnique() now does what common sense requires. + + ---- 2.0r10 --- + - Fixed a problem in the death system that allowed creators to + be undead without quite realizing it. + - Fixed miscellaneous minor gotchas in the sample town. + - Added commands: lightme, quests. + - Tweaked miscellaneous commands. + - Fixed germs, added germ testing lab east of the wiz hall. + + ---- 2.0r9 --- + - Added a <death> channel for kills notices. + - Miscellaneous fixes, tweak, etc. + - Fixed channels bug that changed lognames if someone was listening + to a channel. Now both log. + - Encre now forces the new creator to quit. This is necessary in order + to enable certain characteristics of their new body. + - Fixed a truly vile room bug that leaked objects and memory. + - Added reaper daemon to clean up junk from memory. + - Fixed multiple bugs in lighting system. + - Added light meter to creators' chest. + - Removed roommaker from creators' chest. + - Fixed remaining goto command problem. + - Set EXTRA_TIME_OFFSET in /secure/include/config.h to 0. + - Fixed bug in rescue login. Creators now can use it. + - Reorganized efun man pages and added missing efun and sefun docs. + - Added flying system. + - QCS feature add: you can now add includes and inherits. + - QCS fix: modify <thing> delete <directive> now works properly. + - Added numerous new directives to QCS. + - Added lib object check and NoModify checks to QCS verbs. + - Fixed object manipulation: creatures without prehensile appendages can + no longer accept or manipulate objects. If a creator somehow + manages to lose both hands they can use the "heal" command to fully + restore themselves. + - Fixed a variety of body related issues with races, created a + menagerie of sample npc's for testing. + - Fixed stealing system, added thief class. + - Miscellaneous lib object fixes and additions (eg SetAction now + takes mixed arrays, new SetPermitLoad lfun on npc's, some npc move + messages fixed, etc). + + ---- 2.0r8 --- + - Added intermud announcements to arch room (/secure/room/arch). + - Fixed bug in targeted intermud emotes. + - Channels now log without needing to have a player listening. + - Admin channel now logs to /secure/log + - Fixed lib/std/book.c bug that failed horribly if there was a hidden + file in the text source directory. + - Extensive code cleanup of unused variables. + - Miscellaneous tweaks to sample domain. + - Added tighter restriction to "no teleport" property in rooms. + - Miscellaneous fixes of verb code. + - Modified wrap() sefun to output truncated text rather than just + error out when buffer overflows. + - Added arch command. + - Added EXTRA_TIME_OFFSET parameter to /secure/include/config.h to + accommodate OS'es with peculiar timekeeping. + - Changed local_options to avoid excessive warning messages in /log/errors. + This is only useful if doing a new install of Dead Souls, or + if you copy local_options from the full distribution and recompile + the driver. For the Windows version, all that is needed is to + copy the new driver.exe over the old one, if you're doing an upgrade. + - Rescue login feature added. If when you try to log in, everything + goes to hell, try logging in adding "_rescue" to your name, which + in my case is: cratylus_rescue + - For admins, eval now writes the temp file to /secure, to avoid + annoying /realms dir permission conflicts. + - Cleaned up goto and dest command ugliness. + - Modified reload command and reload() sefun not to perform recursive + updates by default. This should speed up QCS response time and cut + down on mud-wide lag. + - Added some directives to QCS. + + ---- 2.0r7 --- + - Added sample virtual forest to town area. + - Added intermud list of Dead Souls muds to arch room ("read screen"). + - Added mudtime and ticktock commands, and tweaked the time system. + - Updated documentation. + - Added Tim's imc2 client. Doesn't quite work yet. Suggestions welcome. + - Created ds intermud channels ds and ds_test. Enabled ds for cres + by default (i3 names: dead_souls, dead_test4). + - Balanced/fixed attack spells a bit. + - Fixed QCS bug that prevented barkeeps from having stuff added + to their inventories. + - Made it harder to join the mages (The game is too hard for a + first level mage). + - Fixed a bug that made Herkimer a cheat. + - Applied workaround for a bug in Clepius. + + ---- 2.0r6 --- + - Added manuals and such to first admin logon. + - Cleaned up miscellaneous login quirks. + - Got rid of that pesky elog message at startup. + - Updated news files. + + ---- 2.0r5 --- + - Fixed problem with loading a working handbook on first login. + - Fixed QCS bug of reloading files instead of objects. + - Added CREDITS file. + + ---- 2.0r4 --- + - Nailed down nasty bug that overwrote rooms when creating an enter. + - Fixed a bug in "give" code that prevented giving of money. + - Fixed door bug that prevented proper setting of SetLocked and SetClosed. + - Updated some minor documentation unclarities. + - Modified reload() sefun and update command, as well as LastLocation + settings to avoid unnecesary teleportation when reloading objects. + - Modified donate verb and lib object to behave more sanely. + - QCS code cleanup and tightening, also added inits to templates. + - Tightened up sample town code. + - Added Players Handbook + + ---- 2.0r3 --- + - Added workaround for Windows time-of-day problem. + - Fixed minor QCS issues. + + ---- 2.0r2 --- + - Many QCS fixes and updates. + - Added doors and meals to QCS. + - Added thorough QCS documentation: /doc/manual/chapter31 and above. + + ---- 2.0r1 --- + - Fixed peculiar "multiple doors in a room" bug. + diff -c -r --new-file ds1.1/lib/doc/SUPPORT ds2.1/lib/doc/SUPPORT *** ds1.1/lib/doc/SUPPORT Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/SUPPORT Wed Jul 5 00:00:58 2006 *************** *** 0 **** --- 1,22 ---- + Documentation and Support for Dead Souls 2 + + + As of this writing, the Dead Souls project has received + permission to include the old Nightmare docs we'd been missing. + + You can now browse through the build documentation in + the /doc directory. These docs are also conveniently packaged in + a "manual" format. You can find the Creator's Manual in the + chest in your workroom, and it contains this documentation. + + For your convenience, a telnet room has been added to your + mud that can help you connect to Frontiers, so that you may ask + for help if you run into trouble. Just enter the telnet room + west and north of the wizard hall, and type: connect + + You may ask questions of creators there, but + don't be offended if they are more interested in building + their mud than helping you with yours. + + - Cratylus @ Frontiers + 18 December 2005 diff -c -r --new-file ds1.1/lib/doc/applies/__INIT ds2.1/lib/doc/applies/__INIT *** ds1.1/lib/doc/applies/__INIT Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/__INIT Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,9 ---- + __INIT - obsolete apply + + void __INIT(); + + This function used to be called in objects right before create. + global variable initialization is now handled by another function that + cannot be interfered with, so this is no longer called. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/author_file ds2.1/lib/doc/applies/author_file *** ds1.1/lib/doc/applies/author_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/author_file Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,19 ---- + author_file - determine the author for a given object + + string author_file (string file); + + This routine is only used if PACKAGE_MUDLIB_STATS is used. + + This function must exist in the master object. It is called by the + author statistic functions in the driver to determine what author a + given object should be associated with. This is totally arbitrary and + up to the mudlib designers wishes. It should be noted that the author + that the object is assigned to will receive "credit" for all of the + objects behavior (errors, heart_beats, etc). + + See also: + author_stats, + domain_stats, + domain_file + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/catch_tell ds2.1/lib/doc/applies/catch_tell *** ds1.1/lib/doc/applies/catch_tell Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/catch_tell Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,17 ---- + catch_tell - provides an interface to interact with users + + void catch_tell( string message ); + + If INTERACTIVE_CATCH_TELL is defined in options.h, whenever the driver + has something to tell an object due to say(), shout(), tell_object(), etc. + catch_tell in the player object will be called with the message to + be printed. The message can be displayed, discarded, or modified in + any way desired. This is a useful way to have flexible earmuffs, or + to support intelligent clients. + + See also: + message, + receive, + receive_message + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/clean_up ds2.1/lib/doc/applies/clean_up *** ds1.1/lib/doc/applies/clean_up Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/clean_up Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,21 ---- + clean_up - periodically called in inactive objects + + int clean_up( int inherited ); + + The clean_up() function is called by the driver on a regular basis in all + objects that have been inactive for the time specified for clean_up() in the + runtime configuration file. One flag is passed to the function, specifying + whether or not the object has been inheritted by anything. If clean_up() + returns 0, clean_up() will never be called again on that object. If it returns + 1, it will be called again when the object remains inactive for the specified + clean_up() delay. + + One thing that might be commonly done by an object in this function is + destructing itself to conserve memory. However, one often does not want + to destruct objects which have been inherited, as this will cause a new + copy to be loaded next time they are inherited again, causing more than + one copy of the code to be in memory. + + See also: destruct + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/compile_object ds2.1/lib/doc/applies/compile_object *** ds1.1/lib/doc/applies/compile_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/compile_object Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,18 ---- + compile_object - serves as the mudlib interface for the virtual object facility + + object compile_object( string pathname ); + + The driver calls compile_object in the event that the mudlib instructs + the driver to load a file that does not exist. For example, the driver + will call compile_object("/obj/file.r") in master if the mudlib calls + call_other("/obj/file.r", "some_function") or new("/obj/file.r") + and /obj/file.r.c names a file that does not exist. The compile_object() + function is expected to return 0 if the mudlib does not wish to + associate an object with the file name "/obj/file.r". If the mudlib + does wish to associate an object with the filename "/obj/file.r", then + the mudlib should return the object it wishes associated. After an + association is made between an object and a filename, then it will be + as if the file, file.r.c, did exist (to the driver) and when loaded produced + the object that compile_object() returned. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/connect ds2.1/lib/doc/applies/connect *** ds1.1/lib/doc/applies/connect Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/connect Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,17 ---- + connect - get an object for a new user + + object connect(int port); + + The driver calls connect() in the master object whenever a new user logs + into the driver. port is the actual port connected to; for example if + you have two login ports defined as 2000 and 3000, either 2000 or 3000 + will be passed to this routine. + + The object returned by connect() is used as the initial + user object. Note that it is possible to change the user object at a later + time (for example, after determining who is logging in) using the exec() + efun. + + See also: logon, exec + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/crash ds2.1/lib/doc/applies/crash *** ds1.1/lib/doc/applies/crash Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/crash Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,16 ---- + crash - function in master that is called in the event the driver crashes + + void crash( string crash_message, object command_giver, object current_object ); + + The driver calls crash() in master in the event that the driver crashes + (segmentation fault, bus error, etc). This function offers a way to + shutdown the mudlib (safe players and other important data) before the driver + crashes. It also lets you log various useful information such as what + signal crashed the driver, what object was active, who the current player + was etc. + + See also: + shutdown, + slow_shutdown + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/create ds2.1/lib/doc/applies/create *** ds1.1/lib/doc/applies/create Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/create Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,23 ---- + create - object initialization + + void create(...); + + The arguments passed to the function will be the same as those passed to + new() or clone_object() in addition to the filename, if the object was loaded + using either of those efuns. For example, clone_object(file, 3, "hi") will + cause create(3, "hi") to be called in the object after it is created. + + Every object should have a create function defined within it. Within + that function, all initial object initialization should be done. + create() is called on *all* objects. *NOTE* - This behavior is + different than the stock 3.1.2 LPmud driver. In 3.1.2, if an object + is created first by being inherited, then create() wasn't called on + it. In MudOS, this behavior has changed so that it is *always* called + when an object is created. As a result, you may see some odd behavior + if you have a create in a parent object that does a write, you will + see two writes, as if create() had been called twice on the same + object. In reality, create *is* being called twice, but on two + *different* objects: the parent, and the child that is calling + parent::create() manually. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/creator_file ds2.1/lib/doc/applies/creator_file *** ds1.1/lib/doc/applies/creator_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/creator_file Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,23 ---- + creator_file - specifies the uid to give to a newly created object + + string creator_file(string filename); + + This routine is only used if PACKAGE_UIDS is used. + + The creator_file() function is called in the master object each time a new + object is created. The `filename' of the object is passed as the sole + parameter, and the string that creator_file() returns is set as the new + object's uid. If the AUTO_SETEUID option is enabled at compile-time of the + driver, it is also set as the new object's euid. + .PP + One exception: if the AUTO_TRUST_BACKBONE option is enabled at compile-time of + the driver, and creator_file() returns the backbone uid (as specified by + get_bb_uid() in the master object), the object is given the uid and euid of + the object that loaded it. + + See also: + seteuid, + clone_object, + new + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/domain_file ds2.1/lib/doc/applies/domain_file *** ds1.1/lib/doc/applies/domain_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/domain_file Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,17 ---- + domain_file - determine the domain for a given object + + string domain_file( string file ); + + This function must exist in the master object. It is called by the + domain statistic functions in the driver to determine what domain a + given object should be associated with. This is totally arbitrary and + up to the mudlib designers wishes. It should be noted that the domain + that the object is assigned to will receive "credit" for all of the + objects behavior (errors, heart_beats, etc). + + See also: + author_stats, + domain_stats, + author_file + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/epilog ds2.1/lib/doc/applies/epilog *** ds1.1/lib/doc/applies/epilog Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/epilog Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,16 ---- + epilog - handle initialization + + string array epilog( int load_empty ); + + The driver calls epilog() in master after the master object has been loaded. + Required initialization may be done at this point. If epilog() returns an + array of filenames, the driver will attempt to load those files via the + preload() function. + + The variable 'load_empty' is non-zero if the -e option was specified + when starting up the driver, which has been historically used to mean + no preloads, although the mudlib is free to use another interpretation. + + See also: preload + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/error_handler ds2.1/lib/doc/applies/error_handler *** ds1.1/lib/doc/applies/error_handler Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/error_handler Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,42 ---- + error_handler - function in master object to handle errors + + void error_handler( mapping error, int caught ); + + This function is only called if MUDLIB_ERROR_HANDLER is defined. + + This function allows the mudlib to handle runtime errors. + The contents of the 'error' mapping are: + <pre> + ([ + "error" : string, // the error + "program" : string, // the program + "object" : object, // the current object + "line" : int, // the line number + "trace" : mapping array // a trace back + ]) + </pre> + Each line of traceback is a mapping containing the following: + <pre> + ([ + "function" : string, // the function name + "program" : string, // the program + "object" : object, // the object + "file" : string, // the file to which the line number refers + "line" : int, // the line number + "arguments" : array, // function arguments + "locals" : array // local variables + ]) + </pre> + + arguments and local variables are only available if ARGUMENTS_IN_TRACEBACK + and LOCALS_IN_TRACEBACK are defined. + + The 'caught' flag is 1 if the error was trapped by catch(). + + See also: + catch, + error, + throw, + log_error + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/flag ds2.1/lib/doc/applies/flag *** ds1.1/lib/doc/applies/flag Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/flag Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,14 ---- + flag - handle mudlib specific flags specified at driver startup + + void flag( string ); + + This master apply is called for each command line + option passed to the driver with the -f flag. For example, invoking the + driver via: + + ./driver -fdebug + + will call flag("debug") in the master object during initialization. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/applies/get_bb_uid ds2.1/lib/doc/applies/get_bb_uid *** ds1.1/lib/doc/applies/get_bb_uid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/get_bb_uid Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,15 ---- + get_bb_uid - get the backbone uid + + string get_bb_uid(); + + This routine is only used if PACKAGE_UIDS is used. + + This master apply is called by the driver on startup, + after it has loaded the master object, to get the + backbone uid defined by the mud. The function should + return a string, eg "BACKBONE" + + See also: + get_root_uid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/get_root_uid ds2.1/lib/doc/applies/get_root_uid *** ds1.1/lib/doc/applies/get_root_uid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/get_root_uid Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,13 ---- + get_root_uid - get the root uid + + string get_root_uid(); + + This function is only used if PACKAGE_UIDS is used. + + This master apply is called by the driver each time + it loads the master object, to verify that the master + object has loaded, and to get the root uid defined by + the mud. The function should return a string, eg "ROOT" + + See also: + get_bb_uid diff -c -r --new-file ds1.1/lib/doc/applies/get_save_file_name ds2.1/lib/doc/applies/get_save_file_name *** ds1.1/lib/doc/applies/get_save_file_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/get_save_file_name Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,13 ---- + get_save_file_name - back up editor file on abnormal exit + + string get_save_file_name( string file, object who ); + + This master apply is called by ed() when a player disconnects + while in the editor and editing a file. This function + should return an alternate file name for the file to + be saved, to avoid overwriting the original. + + Note: This apply used to be named get_ed_buffer_save_file_name(). + + See also: + ed diff -c -r --new-file ds1.1/lib/doc/applies/heart_beat ds2.1/lib/doc/applies/heart_beat *** ds1.1/lib/doc/applies/heart_beat Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/heart_beat Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,11 ---- + heart_beat - called periodically in objects in which it is enabled + + void heart_beat(); + + If an object has called set_heart_beat(), this function will be called + periodically in that object. + + See also: + set_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/id ds2.1/lib/doc/applies/id *** ds1.1/lib/doc/applies/id Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/id Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,12 ---- + id - function called by present() in order to identify an object + + int id( string an_id ); + + The present() efunction calls id() to determine if a given object is named + by a given string. id() should return 1 if the object wishes to be known + by the name in the string anId; it should return 0 otherwise. + + See also: + present + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/init ds2.1/lib/doc/applies/init *** ds1.1/lib/doc/applies/init Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/init Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,28 ---- + init - function in an object called by move_object() to initialize verb/actions + + void init(); + + This function is not called if NO_ADD_ACTIONS is defined. + + When the mudlib moves an object "A" inside another object "B", the + driver (the move_object() efunction) does the following: + + <DL> + * if "A" is living, causes "A" to call the init() in "B" + * causes each living object in the inventory of "B" to call init() in + "A". regardless of whether "A" is living or not. + * if "A" is living, causes "A" to call the init() in each object in + the inventory of "B". + </DL> + + Note: an object is considered to be living if enable_commands() has + been called by that object. + + Typically, the init() function in an object is used to call add_action() + for each command that the object offers. + + See also: + move_object, + enable_commands, + living, + add_action diff -c -r --new-file ds1.1/lib/doc/applies/interactive/catch_tell ds2.1/lib/doc/applies/interactive/catch_tell *** ds1.1/lib/doc/applies/interactive/catch_tell Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/catch_tell Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + catch_tell - provides an interface to interact with users + + void catch_tell( string message ); + + If INTERACTIVE_CATCH_TELL is defined in options.h, whenever the driver + has something to tell an object due to say(), shout(), tell_object(), etc. + catch_tell in the player object will be called with the message to + be printed. The message can be displayed, discarded, or modified in + any way desired. This is a useful way to have flexible earmuffs, or + to support intelligent clients. + + See also: + message, + receive, + receive_message + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/logon ds2.1/lib/doc/applies/interactive/logon *** ds1.1/lib/doc/applies/interactive/logon Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/logon Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + logon - initialize a logon connection + + object logon(); + + This apply is called on the object returned by the connect() master + apply, after that object has been made into an interactive object, + so the object can initiate any logon sequence which is wanted. This + function is no longer required to exist. this_user() will be the + interactive object. + + See also: connect diff -c -r --new-file ds1.1/lib/doc/applies/interactive/net_dead ds2.1/lib/doc/applies/interactive/net_dead *** ds1.1/lib/doc/applies/interactive/net_dead Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/net_dead Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + net_dead - called by the MudOS driver when an interactive object drops its connection + + void net_dead( void ); + + If an interactive object (i.e. a user object) suddenly loses its + connection (i.e. it goes "net dead"), then the driver calls this + function on that object giving it a chance to clean up, notify its + environment etc. Be aware that functions that depend on the object + being interactive will not work as expected. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/process_input ds2.1/lib/doc/applies/interactive/process_input *** ds1.1/lib/doc/applies/interactive/process_input Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/process_input Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + process_input - inspect (and possibly modify) user input + + mixed process_input( string ); + + If process_input is present in the player object, then the MudOS driver + will send it a copy of each line the player types. If a string is returned, + that string is used as instead of the user input for further processing. + If a non-zero, non-string is returned, no further processing is done. + If zero is returned, processing continues with the original input. + Matching against add_actions is then done. + + Note: If NO_ADD_ACTION is defined, then there is no more processing to be + done after process_input. In this case, the return value is ignored, and + the mudlib is responsible for interpreting the string as a command (or other + user input for non-command based uses). + + See also: add_action + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/receive_message ds2.1/lib/doc/applies/interactive/receive_message *** ds1.1/lib/doc/applies/interactive/receive_message Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/receive_message Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + receive_message - provides the interface used by the message efun. + + void receive_message( mixed cl, mixed message ); + + The message() efun calls this method in the player object. The cl + parameter is typically used to indicate the class (say, tell, emote, + combat, room description, etc) of the message. The receive_message() + apply together with the message() efun can provide a good mechanism for + interfacing with a "smart" client. + + See also: + catch_tell, + message, + receive, + receive_snoop + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/receive_snoop ds2.1/lib/doc/applies/interactive/receive_snoop *** ds1.1/lib/doc/applies/interactive/receive_snoop Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/receive_snoop Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + receive_snoop - catch incoming snoop text + + void receive_snoop(string message); + + If RECEIVE_SNOOP is defined in options.h or local_options, + whenever a user is snooping another + user, all snoop text is sent to receive_snoop() in their user object. Inside + of this function, you can do as you wish with the text. A common activity + would be to receive() it. + + See also: + catch_tell, receive + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/telnet_suboption ds2.1/lib/doc/applies/interactive/telnet_suboption *** ds1.1/lib/doc/applies/interactive/telnet_suboption Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/telnet_suboption Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + telnet_suboption - process telnet suboptions + + void telnet_suboption( string buf ); + + This apply is called on the interactive object with the parameter given + by the SE telnet suboption, for mudlib defined processing. Note that + terminal type responses and window size responses are interpreted and + sent to terminal_type() and window_size() respectively instead of going + through telnet_suboption(). + + The first byte of the buffer is typically a type descriptor, + ie TELOPT_TTYPE. The next byte is a procession option, such + as TELQUAL_IS. Following this is the type dependent data. + + See also: terminal_type, window_size + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/terminal_type ds2.1/lib/doc/applies/interactive/terminal_type *** ds1.1/lib/doc/applies/interactive/terminal_type Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/terminal_type Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + terminal_type - inform the mudlib of the user's terminal type + + void terminal_type( string term ); + + This apply is called on the interactive object with term set to the + terminal type for the user, as reported by telnet negotiation. If the + user's client never responds (it's not telnet, for example) this will + never be called. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/window_size ds2.1/lib/doc/applies/interactive/window_size *** ds1.1/lib/doc/applies/interactive/window_size Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/window_size Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + window_size - report the users window size + + void window_size(int width, int height); + + window_size() is called with the user's window size, as reported by telnet + negotiation. If the user's client never responds to the query, this is + never called. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/interactive/write_prompt ds2.1/lib/doc/applies/interactive/write_prompt *** ds1.1/lib/doc/applies/interactive/write_prompt Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/interactive/write_prompt Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + write_prompt - called when the parser wants a prompt to be written. + + void write_prompt(); + + If write_prompt is present in the player object, the driver will call it + whenever the default prompt would normally be printed. The driver will + not call write_prompt when the player is in input_to or ed. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/log_error ds2.1/lib/doc/applies/log_error *** ds1.1/lib/doc/applies/log_error Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/log_error Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,14 ---- + log_error - log errors intelligently + + void log_error( string file, string message ); + + Whenever an error occurs during compilation, the function log_error in + the master object is called with the filename that the error occurred + in and the error message itself. Then, log_error is free to do + whatever it thinks it should do with that information. Usually this + is deciding based on the filename where the error message should be + logged, and then writing it to that file. Warnings also pass through + this routine, and can be detected since they start with "Warning:" + + See also: + error_handler diff -c -r --new-file ds1.1/lib/doc/applies/logon ds2.1/lib/doc/applies/logon *** ds1.1/lib/doc/applies/logon Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/logon Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,11 ---- + logon - initialize a logon connection + + object logon(); + + This apply is called on the object returned by the connect() master + apply, after that object has been made into an interactive object, + so the object can initiate any logon sequence which is wanted. This + function is no longer required to exist. this_user() will be the + interactive object. + + See also: connect diff -c -r --new-file ds1.1/lib/doc/applies/make_path_absolute ds2.1/lib/doc/applies/make_path_absolute *** ds1.1/lib/doc/applies/make_path_absolute Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/make_path_absolute Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,10 ---- + make_path_absolute - resolve relative path name + + string make_path_absolute( string rel_path ); + + This master apply is called by the ed() efun to + resolve relative path names of a file to read/write, to an absolute path + name. + + See also: + ed diff -c -r --new-file ds1.1/lib/doc/applies/master/author_file ds2.1/lib/doc/applies/master/author_file *** ds1.1/lib/doc/applies/master/author_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/author_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + author_file - determine the author for a given object + + string author_file (string file); + + This routine is only used if PACKAGE_MUDLIB_STATS is used. + + This function must exist in the master object. It is called by the + author statistic functions in the driver to determine what author a + given object should be associated with. This is totally arbitrary and + up to the mudlib designers wishes. It should be noted that the author + that the object is assigned to will receive "credit" for all of the + objects behavior (errors, heart_beats, etc). + + See also: + author_stats, + domain_stats, + domain_file + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/compile_object ds2.1/lib/doc/applies/master/compile_object *** ds1.1/lib/doc/applies/master/compile_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/compile_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + compile_object - serves as the mudlib interface for the virtual object facility + + object compile_object( string pathname ); + + The driver calls compile_object in the event that the mudlib instructs + the driver to load a file that does not exist. For example, the driver + will call compile_object("/obj/file.r") in master if the mudlib calls + call_other("/obj/file.r", "some_function") or new("/obj/file.r") + and /obj/file.r.c names a file that does not exist. The compile_object() + function is expected to return 0 if the mudlib does not wish to + associate an object with the file name "/obj/file.r". If the mudlib + does wish to associate an object with the filename "/obj/file.r", then + the mudlib should return the object it wishes associated. After an + association is made between an object and a filename, then it will be + as if the file, file.r.c, did exist (to the driver) and when loaded produced + the object that compile_object() returned. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/connect ds2.1/lib/doc/applies/master/connect *** ds1.1/lib/doc/applies/master/connect Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/connect Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + connect - get an object for a new user + + object connect(int port); + + The driver calls connect() in the master object whenever a new user logs + into the driver. port is the actual port connected to; for example if + you have two login ports defined as 2000 and 3000, either 2000 or 3000 + will be passed to this routine. + + The object returned by connect() is used as the initial + user object. Note that it is possible to change the user object at a later + time (for example, after determining who is logging in) using the exec() + efun. + + See also: logon, exec + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/crash ds2.1/lib/doc/applies/master/crash *** ds1.1/lib/doc/applies/master/crash Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/crash Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + crash - function in master that is called in the event the driver crashes + + void crash( string crash_message, object command_giver, object current_object ); + + The driver calls crash() in master in the event that the driver crashes + (segmentation fault, bus error, etc). This function offers a way to + shutdown the mudlib (safe players and other important data) before the driver + crashes. It also lets you log various useful information such as what + signal crashed the driver, what object was active, who the current player + was etc. + + See also: + shutdown, + slow_shutdown + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/creator_file ds2.1/lib/doc/applies/master/creator_file *** ds1.1/lib/doc/applies/master/creator_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/creator_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + creator_file - specifies the uid to give to a newly created object + + string creator_file(string filename); + + This routine is only used if PACKAGE_UIDS is used. + + The creator_file() function is called in the master object each time a new + object is created. The `filename' of the object is passed as the sole + parameter, and the string that creator_file() returns is set as the new + object's uid. If the AUTO_SETEUID option is enabled at compile-time of the + driver, it is also set as the new object's euid. + .PP + One exception: if the AUTO_TRUST_BACKBONE option is enabled at compile-time of + the driver, and creator_file() returns the backbone uid (as specified by + get_bb_uid() in the master object), the object is given the uid and euid of + the object that loaded it. + + See also: + seteuid, + clone_object, + new + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/domain_file ds2.1/lib/doc/applies/master/domain_file *** ds1.1/lib/doc/applies/master/domain_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/domain_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + domain_file - determine the domain for a given object + + string domain_file( string file ); + + This function must exist in the master object. It is called by the + domain statistic functions in the driver to determine what domain a + given object should be associated with. This is totally arbitrary and + up to the mudlib designers wishes. It should be noted that the domain + that the object is assigned to will receive "credit" for all of the + objects behavior (errors, heart_beats, etc). + + See also: + author_stats, + domain_stats, + author_file + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/epilog ds2.1/lib/doc/applies/master/epilog *** ds1.1/lib/doc/applies/master/epilog Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/epilog Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + epilog - handle initialization + + string array epilog( int load_empty ); + + The driver calls epilog() in master after the master object has been loaded. + Required initialization may be done at this point. If epilog() returns an + array of filenames, the driver will attempt to load those files via the + preload() function. + + The variable 'load_empty' is non-zero if the -e option was specified + when starting up the driver, which has been historically used to mean + no preloads, although the mudlib is free to use another interpretation. + + See also: preload + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/error_handler ds2.1/lib/doc/applies/master/error_handler *** ds1.1/lib/doc/applies/master/error_handler Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/error_handler Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,42 ---- + error_handler - function in master object to handle errors + + void error_handler( mapping error, int caught ); + + This function is only called if MUDLIB_ERROR_HANDLER is defined. + + This function allows the mudlib to handle runtime errors. + The contents of the 'error' mapping are: + <pre> + ([ + "error" : string, // the error + "program" : string, // the program + "object" : object, // the current object + "line" : int, // the line number + "trace" : mapping array // a trace back + ]) + </pre> + Each line of traceback is a mapping containing the following: + <pre> + ([ + "function" : string, // the function name + "program" : string, // the program + "object" : object, // the object + "file" : string, // the file to which the line number refers + "line" : int, // the line number + "arguments" : array, // function arguments + "locals" : array // local variables + ]) + </pre> + + arguments and local variables are only available if ARGUMENTS_IN_TRACEBACK + and LOCALS_IN_TRACEBACK are defined. + + The 'caught' flag is 1 if the error was trapped by catch(). + + See also: + catch, + error, + throw, + log_error + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/flag ds2.1/lib/doc/applies/master/flag *** ds1.1/lib/doc/applies/master/flag Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/flag Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + flag - handle mudlib specific flags specified at driver startup + + void flag( string ); + + This master apply is called for each command line + option passed to the driver with the -f flag. For example, invoking the + driver via: + + ./driver -fdebug + + will call flag("debug") in the master object during initialization. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/applies/master/get_bb_uid ds2.1/lib/doc/applies/master/get_bb_uid *** ds1.1/lib/doc/applies/master/get_bb_uid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/get_bb_uid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + get_bb_uid - get the backbone uid + + string get_bb_uid(); + + This routine is only used if PACKAGE_UIDS is used. + + This master apply is called by the driver on startup, + after it has loaded the master object, to get the + backbone uid defined by the mud. The function should + return a string, eg "BACKBONE" + + See also: + get_root_uid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/get_root_uid ds2.1/lib/doc/applies/master/get_root_uid *** ds1.1/lib/doc/applies/master/get_root_uid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/get_root_uid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + get_root_uid - get the root uid + + string get_root_uid(); + + This function is only used if PACKAGE_UIDS is used. + + This master apply is called by the driver each time + it loads the master object, to verify that the master + object has loaded, and to get the root uid defined by + the mud. The function should return a string, eg "ROOT" + + See also: + get_bb_uid diff -c -r --new-file ds1.1/lib/doc/applies/master/get_save_file_name ds2.1/lib/doc/applies/master/get_save_file_name *** ds1.1/lib/doc/applies/master/get_save_file_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/get_save_file_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + get_save_file_name - back up editor file on abnormal exit + + string get_save_file_name( string file, object who ); + + This master apply is called by ed() when a player disconnects + while in the editor and editing a file. This function + should return an alternate file name for the file to + be saved, to avoid overwriting the original. + + Note: This apply used to be named get_ed_buffer_save_file_name(). + + See also: + ed diff -c -r --new-file ds1.1/lib/doc/applies/master/log_error ds2.1/lib/doc/applies/master/log_error *** ds1.1/lib/doc/applies/master/log_error Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/log_error Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + log_error - log errors intelligently + + void log_error( string file, string message ); + + Whenever an error occurs during compilation, the function log_error in + the master object is called with the filename that the error occurred + in and the error message itself. Then, log_error is free to do + whatever it thinks it should do with that information. Usually this + is deciding based on the filename where the error message should be + logged, and then writing it to that file. Warnings also pass through + this routine, and can be detected since they start with "Warning:" + + See also: + error_handler diff -c -r --new-file ds1.1/lib/doc/applies/master/make_path_absolute ds2.1/lib/doc/applies/master/make_path_absolute *** ds1.1/lib/doc/applies/master/make_path_absolute Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/make_path_absolute Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + make_path_absolute - resolve relative path name + + string make_path_absolute( string rel_path ); + + This master apply is called by the ed() efun to + resolve relative path names of a file to read/write, to an absolute path + name. + + See also: + ed diff -c -r --new-file ds1.1/lib/doc/applies/master/object_name ds2.1/lib/doc/applies/master/object_name *** ds1.1/lib/doc/applies/master/object_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/object_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + object_name - called by the driver to find out an object's name + + string object_name( object ); + + This master apply is called by the sprintf() efun, when + printing the "value" of an object. This function should + return a string corresponding to the name of the object + (eg a user's name). + + See also: + file_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/parse_command_all_word ds2.1/lib/doc/applies/master/parse_command_all_word *** ds1.1/lib/doc/applies/master/parse_command_all_word Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/parse_command_all_word Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + parse_command_all_word - find out what word refers to everything + + string parse_command_all_word(); + + This routine is called in the master object to find out what word should + be considered to refer to everyting. It is used by the parse_command() efun. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/master/parse_command_prepos_list ds2.1/lib/doc/applies/master/parse_command_prepos_list *** ds1.1/lib/doc/applies/master/parse_command_prepos_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/parse_command_prepos_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_prepos_list - find out what words are valid prepositions + + string array parse_command_prepos_list(); + + This routine is called in the master object to find out what words should + be considered prepositions. It is used by the parsing package and the + parse_command() efun. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/master/preload ds2.1/lib/doc/applies/master/preload *** ds1.1/lib/doc/applies/master/preload Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/preload Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + preload - preload an object into memory + + void preload( string filename ); + + For each string in the array returned by epilog, the driver calls + preload(filename). Note that there is the equivalent of a catch() around + these calls at the driver level, so it is not neccessary for the mudlib + to worry about the sequence being terminated by an error. + + Typical behavoir is to use load_object() to attempt to load the file. + + See also: preload, , + load_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/privs_file ds2.1/lib/doc/applies/master/privs_file *** ds1.1/lib/doc/applies/master/privs_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/privs_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + privs_file - specifies the privs string to give to a newly created object + + string privs_file( string filename ); + + The privs_file() function is called in the master object when a new file + is created. The `filename' of the object is passed as the argument, and + the string that privs_file() returns is used as the new object's privs + string. + + The privs_file() functionality is only available if the driver is compiled + with the PRIVS option defined. + + See also: + query_privs + set_privs diff -c -r --new-file ds1.1/lib/doc/applies/master/retrieve_ed_setup ds2.1/lib/doc/applies/master/retrieve_ed_setup *** ds1.1/lib/doc/applies/master/retrieve_ed_setup Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/retrieve_ed_setup Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + retrieve_ed_setup - retrieve a user's editor setup or configuration settings + + int retrieve_ed_setup( object user ); + + This master apply is called by the ed() efun to retrieve + a user's ed setup/configuration settings. This function + should return the setup (contained in an int). + + See also: + save_ed_setup diff -c -r --new-file ds1.1/lib/doc/applies/master/save_ed_setup ds2.1/lib/doc/applies/master/save_ed_setup *** ds1.1/lib/doc/applies/master/save_ed_setup Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/save_ed_setup Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + save_ed_setup - save a user's editor setup or configuration settings + + int save_ed_setup( object user, int config ); + + This master apply is called by the ed() efun to save + a user's ed setup/configuration settings (contained in + an int). This function should return an int for + success (1 or TRUE)/failure (0 or FALSE). + + Seel also: + retrieve_ed_setup diff -c -r --new-file ds1.1/lib/doc/applies/master/slow_shutdown ds2.1/lib/doc/applies/master/slow_shutdown *** ds1.1/lib/doc/applies/master/slow_shutdown Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/slow_shutdown Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + slow_shutdown - informs the mud that a slow shutdown is in progress + + int slow_shutdown( int minutes ); + + This master apply is called when the driver can't + allocate any more memory from the heap and had to + use its reserved memory block. This function can + only be called if the "reserved size" config file + setting was set. The minutes remaining to driver + shutdown is passed to this function. If this function + does ont exist, or returns zero, the driver shuts + down immediately. + + See also: + crash, + shutdown + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_bind ds2.1/lib/doc/applies/master/valid_bind *** ds1.1/lib/doc/applies/master/valid_bind Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_bind Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + valid_bind - determine if it is legal to bind a given function pointer to an object + + int valid_bind(object doer, object owner, object victim); + + This is called when 'doer' tries to use the bind() efun to bind a function + pointer owned by 'owner' to the object 'victim'. If this routine returns + zero, the operation is disallowed. + + See also: + bind + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_compile_to_c ds2.1/lib/doc/applies/master/valid_compile_to_c *** ds1.1/lib/doc/applies/master/valid_compile_to_c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_compile_to_c Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + valid_compile_to_c - determine whether LPC->C compilation may take place + + int valid_compile_to_c(); + + valid_compile_to_c() is called when the generate_source() efun is used to + generate C files or to do runtime compilation of an object. One might + want to restrict the use of this since the process can be CPU intensive. + + See also: generate_source + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_hide ds2.1/lib/doc/applies/master/valid_hide *** ds1.1/lib/doc/applies/master/valid_hide Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_hide Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + valid_hide - allows or disallows objects to hide and see hidden objects + + int valid_hide( object ob ); + + Add valid_hide to master.c in order to allow objects to hide themselves, + or see other objects that have hidden themselves. When an object tries to + use the set_hide() efun to hide itself, valid_hide will be called with the + object that is wanting to hide as the sole parameter. It should return 1 + to allow it, or 0 to not allow it. The same call takes place when it needs + to be determined if a certain object should be able to see hidden objects. + + See also: + set_hide + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_link ds2.1/lib/doc/applies/master/valid_link *** ds1.1/lib/doc/applies/master/valid_link Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_link Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + valid_link - controls the use of the link efun + + int valid_link( string from, string to ); + + The driver calls valid_link(from, to) in the master object from inside the + link(from, to) efunction. If valid_link() returns 0, then the link() + will fail. If valid_link() returns 1, then the link will succeed if + rename() would succeed if called with the same arguments. + + See also: + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_object ds2.1/lib/doc/applies/master/valid_object *** ds1.1/lib/doc/applies/master/valid_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + valid_object - allows control over which objects can be loaded + + int valid_object( object obj ); + + After loading an object, the driver will call valid_object() with the newly + created object as its argument, in the master object. If the function + exists, and returns 0, then the object will be destructed and the efun that + caused it to load will error out. If it does not exist, or returns 1, then + loading will proceed as normal. This is called before the object has a + chance to execute any code, including create(), so not much should be + assumed about the object except that file_name(obj) is valid. + + See also: + valid_override diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_override ds2.1/lib/doc/applies/master/valid_override *** ds1.1/lib/doc/applies/master/valid_override Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_override Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,48 ---- + valid_override - controls the use of efun:: + + int valid_override( string file, string efun_name, string mainfile ); + + File will be the actual file the call appears in; mainfile will be the file + being compiled (the two can differ due to #include) + + Add valid_override to master.c in order to control the use of the efun:: + prefix. The valid_override function in master.c will be called each + time the driver attempts to compile a function call that begins with + efun::. If valid_override returns 0, then that compile will fail. Thus + valid_override provides a way to modify the behavior of efuns that isn't + circumventable via the efun:: prefix (by having a simul_efun of the same + name as the efun to be modified and having valid_override disallow that + simul_efun from being overriden). + + If you wish to have the original 3.1.2 efun:: behavior, simply add + a line to master.c that looks like this: + + <pre> + int valid_override(string file, string efun) { return 1; } + </pre> + + Here is an example valid_override that is more restrictive: + <pre> + int + valid_override(string file, string name) + { + if (file == "/adm/obj/simul_efun") { + return 1; + } + if (name == "destruct") + return 0; + if (name == "shutdown") + return 0; + if (name == "snoop") + return 0; + if (name == "exec") + return 0; + return 1; + } + </pre> + + See also: + valid_object, + function_exists + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_read ds2.1/lib/doc/applies/master/valid_read *** ds1.1/lib/doc/applies/master/valid_read Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_read Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + valid_read - checks if a certain person has read permission on a file + + int valid_read( string file, object user, string func ); + + Every time an object tries to read a file, the driver calls valid_read + in the master object to check if the read should be allowed. The + arguments are the filename, the object making the read, and + the calling function name. If valid_read returns non-zero, the read is + allowed. + + See also: + valid_write + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_save_binary ds2.1/lib/doc/applies/master/valid_save_binary *** ds1.1/lib/doc/applies/master/valid_save_binary Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_save_binary Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + valid_save_binary - controls whether or not an object can save its loaded program + + int valid_save_binary( string file ); + + This routine is only used when BINARIES are enabled. + + When the driver is compiled with ALWAYS_SAVE_BINARIES, or an object uses + '#pragma save_binary', valid_save_binary is called with the program's filename. + If valid_save_binary returns 1, then the program will be saved to disk for + faster reloading, otherwise it will not be saved, and the next reload will + recompile as usual. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_seteuid ds2.1/lib/doc/applies/master/valid_seteuid *** ds1.1/lib/doc/applies/master/valid_seteuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_seteuid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + valid_seteuid - secures the use of seteuid + + int valid_seteuid( object obj, string euid ); + + This routine is only used if PACKAGE_UIDS is defined. + + The driver calls valid_seteuid(ob, euid) in the master object from inside the + seteuid(euid) efunction. If valid_seteuid() returns 0, then the seteuid() + call will fail. If valid_seteuid() returns 1, then the seteuid() will + succeed. + + See also: + seteuid, + geteuid, + getuid, + export_uid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_shadow ds2.1/lib/doc/applies/master/valid_shadow *** ds1.1/lib/doc/applies/master/valid_shadow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_shadow Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + valid_shadow - controls which objects can be shadowed + + int valid_shadow( object ob ); + + When an object attempts to shadow `ob' (with the shadow() efun), valid_shadow + in the master object is called. One object parameter is passed, which is the + object that previous_object() is attempting to shadow. valid_shadow() should + return 0 if the shadow should not be permitted, in which case the shadow() call + will return 0 and fail. If valid_shadow() returns 1, the shadow is allowed. + + See also: + shadow, + query_shadowing + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_socket ds2.1/lib/doc/applies/master/valid_socket *** ds1.1/lib/doc/applies/master/valid_socket Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_socket Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + valid_socket - protects the socket efunctions + + int valid_socket( object caller, string function, mixed array info ); + + Each of the socket efunctions calls valid_socket() prior to executing. + If valid_socket returns 0, then the socket efunction fails. If + valid_socket returns 1, then the socket efunction attempts to succeed. + The first argument 'caller' is the object that called the socket efunction. + The second argument is the name of the socket efunction that is being + called (e.g. socket_write() or socket_bind()). The third argument is + an array of information. The first element of the array (when applicable) + is file descriptor being referenced. The second element of the array + is the owner of the socket (object). The third element of the array is + the address (string) of the remote end of the socket. The fourth element + of the array is the port number associated with the socket. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/master/valid_write ds2.1/lib/doc/applies/master/valid_write *** ds1.1/lib/doc/applies/master/valid_write Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/master/valid_write Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + valid_write - checks if a certain object has write permission on a file + + int valid_write( string file, object ob, string func ); + + Every time an object tries to write a file, the driver calls valid_write + in the master object to check if the write should be allowed. The + arguments are the filename, the object making the write, and + the calling function name (usually the name of the efun being used). + If valid_write returns non-zero, the write is allowed. + + See also: + valid_read + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/move_or_destruct ds2.1/lib/doc/applies/move_or_destruct *** ds1.1/lib/doc/applies/move_or_destruct Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/move_or_destruct Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,12 ---- + move_or_destruct - ask an object to move to the specified destination + + int move_or_destruct( object dest ); + + If an object's environment is destructed, this apply is called on it's + contents. 'dest' will be the environment of the destructing object, + or zero if it has none. If the object does not move itself out of + the object being destructed, it will be destructed as well. + + See also: + destruct, + move_object diff -c -r --new-file ds1.1/lib/doc/applies/net_dead ds2.1/lib/doc/applies/net_dead *** ds1.1/lib/doc/applies/net_dead Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/net_dead Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,11 ---- + net_dead - called by the MudOS driver when an interactive object drops its connection + + void net_dead( void ); + + If an interactive object (i.e. a user object) suddenly loses its + connection (i.e. it goes "net dead"), then the driver calls this + function on that object giving it a chance to clean up, notify its + environment etc. Be aware that functions that depend on the object + being interactive will not work as expected. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/object_name ds2.1/lib/doc/applies/object_name *** ds1.1/lib/doc/applies/object_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/object_name Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,13 ---- + object_name - called by the driver to find out an object's name + + string object_name( object ); + + This master apply is called by the sprintf() efun, when + printing the "value" of an object. This function should + return a string corresponding to the name of the object + (eg a user's name). + + See also: + file_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/parse_command ds2.1/lib/doc/applies/parse_command *** ds1.1/lib/doc/applies/parse_command Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parse_command Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,213 ---- + + parse_command(3) LPC Library Functions parse_command(3) + + NNAAMMEE + parse_command() - try to match a string with a given pat- + tern + + SSYYNNOOPPSSIISS + int parse_command( string command, object env|object *oblist, + string pattern, mixed arg, ... ); + + DDEESSCCRRIIPPTTIIOONN + parse_command() is a piffed up sscanf(3) operating on word + basis. It works similar to sscanf(3) in that it takes a + pattern and a variable set of destination arguments. It is + together with sscanf(3) the only efun to use pass by ref- + erence for other variables than arrays. That is, + parse_command() returns values in its arguments. + + parse_command() returns 1 if 'command' is considered to + have matched + + The 'env' or 'oblist' parameter either holds an object or + a list of objects. If it holds a single object than a list + of objects are automatically created by adding the + deep_inventory of the object, ie this is identical: + + parse_command(cmd, environment(), pattern, arg) + + and + + parse_command( cmd, ({ environment() }) + + deep_inventory(environment()), pattern, arg) + + Example string = " 'get' / 'take' %i " + Syntax: + 'word' obligatory text + [word] optional text + / Alternative marker + %o Single item, object + %l Living objects + %s Any text + %w Any word + %p One of a list (prepositions) + %i Any items + %d Number 0- or tx(0-99) + + The 'arg' list is zero or more arguments. These are the + result variables as in sscanf. Note that one variable is + needed for each %_ + + The return types of different %_ is: + %o Returns an object + %s Returns a string of words + + MudOS 5 Sep 1994 1 + + parse_command(3) LPC Library Functions parse_command(3) + + %w Returns a string of one word + %p Can on entry hold a list of word in array + or an empty variable + Returns: + if empty variable: a string + if array: array[0] = matched word + %i Returns a special array on the form: + [0] = (int) +(wanted) -(order) 0(all) + [1..n] (object) Objectpointers + %l Returns a special array on the form: + [0] = (int) +(wanted) -(order) 0(all) + [1..n] (object) Objectpointers + These are only living objects. + %d Returns a number + + The only types of % that uses all the loaded information + from the objects are %i and %l. These are in fact identi- + cal except that %l filters out all nonliving objects from + the list of objects before trying to parse. + + The return values of %i and %l is also the most complex. + They return an array consisting of first a number and then + all possible objects matching. As the typical string + matched by %i/%l looks like: 'three red roses', of these + numerical constructs was matched: + + if numeral >0 then three, four, five etc were matched + if numeral <0 then second, twentyfirst etc were matched + if numeral==0 then 'all' or a generic plural form such as + 'apples' were matched. + + NOTE! + + The efun makes no semantic implication on the + given numeral. It does + not matter if 'all apples' or 'second apple' is + given. A %i will + return ALL possible objects matching in the + array. It is up to the + caller to decide what 'second' means in a given + context. + Also when given an object and not an explicit + array of objects the + entire recursive inventory of the given object is + searched. It is up + to the caller to decide which of the objects are + actually visible + meaning that 'second' might not at all mean the + second object in + the returned array of objects. + + CCAAVVEEAATT + Patterns of type: "%s %w %i" Might not work as one would + + MudOS 5 Sep 1994 2 + + parse_command(3) LPC Library Functions parse_command(3) + + expect. %w will always succeed so the arg corresponding + to %s will always be empty. + + BBUUGGSS + Patterns of the type: 'word' and [word] The 'word' can not + contain spaces. It must be a single word. This is so + because the pattern is exploded on " " (space) and a pat- + tern element can therefore not contain spaces. + + As another effect of the exploding on space, separate + pieces of a pattern MUST be separated with space, ie not " + 'word'/%i " but " 'word' / %i" + + EXAMPLE: + if (parse_command("spray car",environment(this_player()), + " 'spray' / 'paint' [paint] %i ",items)) + { + /* + If the pattern matched then items holds a return array as + described under 'destargs' %i above. + */ + } + + MUDLIB SUPPORT + + To make the efun useful it must have a certain support + from the mudlib, there is a set of functions that it needs + to call to get relevant information before it can parse in + a sensible manner. + + In earlier versions it used the normal id() lfun in the + LPC objects to find out if a given object was identified + by a certain string. This was highly inefficient as it + could result in hundreds or maybe thousands of calls when + very long commands were parsed. + + The new version relies on the LPC objects to give it three + lists of 'names'. + + 1 - The normal singular names. + 2 - The plural forms of the names. + 3 - The acknowledged adjectives of the object. + + These are fetched by calls to the functions: + + 1 - string *parse_command_id_list(); + 2 - string *parse_command_plural_id_list(); + 3 - string *parse_command_adjectiv_id_list(); + + The only really needed list is the first. If the second + does not exist than the efun will try to create one from + the singluar list. For grammatical reasons it does not + always succeed in a perfect way. This is especially true + + MudOS 5 Sep 1994 3 + + parse_command(3) LPC Library Functions parse_command(3) + + when the 'names' are not single words but phrases. + + The third is very nice to have because it makes constructs + like + + Apart from these functions that should exist in all + objects, and which are therefore best put in the base + mudlib object there is also a set of functions needed in + the master object. These are not absolutely necessary but + they give extra power to the efun. + + Basically these master object lfuns are there to give + default values for the lists of names fetched from each + object. + + The names in these lists are applicable to any and all + objects, the first three are identical to the lfuns in the + objects: + + string *parse_command_id_list() + - Would normally return: ({ "one", "thing" }) + + string *parse_command_plural_id_list() + - Would normally return: ({ "ones", "things", "them" }) + + string *parse_command_adjectiv_id_list() + - Would normally return ({ "iffish" }) + + The last two are the default list of the prepositions and + a single so called + string *parse_command_prepos_list() + - Would normally return: ({ "in", "on", "under" }) + + string parse_command_all_word() + - Would normally return: "all" + + MudOS 5 Sep 1994 4 + diff -c -r --new-file ds1.1/lib/doc/applies/parse_command_adjectiv_id_list ds2.1/lib/doc/applies/parse_command_adjectiv_id_list *** ds1.1/lib/doc/applies/parse_command_adjectiv_id_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parse_command_adjectiv_id_list Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_adjectiv_id_list - returns a list of names to the parser + + string array parse_command_adjectiv_id_list(); [sic] + + This routine is used to find out what adjectives the object responds to, and is + used by the parsing package and the parse_command() efun. In addition, + anything returned by the master object will work on ANY object. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/parse_command_all_word ds2.1/lib/doc/applies/parse_command_all_word *** ds1.1/lib/doc/applies/parse_command_all_word Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parse_command_all_word Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,9 ---- + parse_command_all_word - find out what word refers to everything + + string parse_command_all_word(); + + This routine is called in the master object to find out what word should + be considered to refer to everyting. It is used by the parse_command() efun. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/parse_command_id_list ds2.1/lib/doc/applies/parse_command_id_list *** ds1.1/lib/doc/applies/parse_command_id_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parse_command_id_list Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_id_list - returns a list of names to the parser + + string array parse_command_id_list(); + + This routine is used to find out what nouns the object responds to, and is + used by the parsing package and the parse_command() efun. In addition, + anything returned by the master object will work on ANY object. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/parse_command_plural_id_list ds2.1/lib/doc/applies/parse_command_plural_id_list *** ds1.1/lib/doc/applies/parse_command_plural_id_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parse_command_plural_id_list Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_plural_id_list - returns a list of names to the parser + + string array parse_command_plural_id_list(); + + This routine is used to find out what plural nouns the object responds to, + and is used by the parsing package and the parse_command() efun. In addition, + anything returned by the master object will work on ANY object. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/parse_command_prepos_list ds2.1/lib/doc/applies/parse_command_prepos_list *** ds1.1/lib/doc/applies/parse_command_prepos_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parse_command_prepos_list Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_prepos_list - find out what words are valid prepositions + + string array parse_command_prepos_list(); + + This routine is called in the master object to find out what words should + be considered prepositions. It is used by the parsing package and the + parse_command() efun. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/parsing/parse_command ds2.1/lib/doc/applies/parsing/parse_command *** ds1.1/lib/doc/applies/parsing/parse_command Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parsing/parse_command Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,213 ---- + + parse_command(3) LPC Library Functions parse_command(3) + + NNAAMMEE + parse_command() - try to match a string with a given pat- + tern + + SSYYNNOOPPSSIISS + int parse_command( string command, object env|object *oblist, + string pattern, mixed arg, ... ); + + DDEESSCCRRIIPPTTIIOONN + parse_command() is a piffed up sscanf(3) operating on word + basis. It works similar to sscanf(3) in that it takes a + pattern and a variable set of destination arguments. It is + together with sscanf(3) the only efun to use pass by ref- + erence for other variables than arrays. That is, + parse_command() returns values in its arguments. + + parse_command() returns 1 if 'command' is considered to + have matched + + The 'env' or 'oblist' parameter either holds an object or + a list of objects. If it holds a single object than a list + of objects are automatically created by adding the + deep_inventory of the object, ie this is identical: + + parse_command(cmd, environment(), pattern, arg) + + and + + parse_command( cmd, ({ environment() }) + + deep_inventory(environment()), pattern, arg) + + Example string = " 'get' / 'take' %i " + Syntax: + 'word' obligatory text + [word] optional text + / Alternative marker + %o Single item, object + %l Living objects + %s Any text + %w Any word + %p One of a list (prepositions) + %i Any items + %d Number 0- or tx(0-99) + + The 'arg' list is zero or more arguments. These are the + result variables as in sscanf. Note that one variable is + needed for each %_ + + The return types of different %_ is: + %o Returns an object + %s Returns a string of words + + MudOS 5 Sep 1994 1 + + parse_command(3) LPC Library Functions parse_command(3) + + %w Returns a string of one word + %p Can on entry hold a list of word in array + or an empty variable + Returns: + if empty variable: a string + if array: array[0] = matched word + %i Returns a special array on the form: + [0] = (int) +(wanted) -(order) 0(all) + [1..n] (object) Objectpointers + %l Returns a special array on the form: + [0] = (int) +(wanted) -(order) 0(all) + [1..n] (object) Objectpointers + These are only living objects. + %d Returns a number + + The only types of % that uses all the loaded information + from the objects are %i and %l. These are in fact identi- + cal except that %l filters out all nonliving objects from + the list of objects before trying to parse. + + The return values of %i and %l is also the most complex. + They return an array consisting of first a number and then + all possible objects matching. As the typical string + matched by %i/%l looks like: 'three red roses', of these + numerical constructs was matched: + + if numeral >0 then three, four, five etc were matched + if numeral <0 then second, twentyfirst etc were matched + if numeral==0 then 'all' or a generic plural form such as + 'apples' were matched. + + NOTE! + + The efun makes no semantic implication on the + given numeral. It does + not matter if 'all apples' or 'second apple' is + given. A %i will + return ALL possible objects matching in the + array. It is up to the + caller to decide what 'second' means in a given + context. + Also when given an object and not an explicit + array of objects the + entire recursive inventory of the given object is + searched. It is up + to the caller to decide which of the objects are + actually visible + meaning that 'second' might not at all mean the + second object in + the returned array of objects. + + CCAAVVEEAATT + Patterns of type: "%s %w %i" Might not work as one would + + MudOS 5 Sep 1994 2 + + parse_command(3) LPC Library Functions parse_command(3) + + expect. %w will always succeed so the arg corresponding + to %s will always be empty. + + BBUUGGSS + Patterns of the type: 'word' and [word] The 'word' can not + contain spaces. It must be a single word. This is so + because the pattern is exploded on " " (space) and a pat- + tern element can therefore not contain spaces. + + As another effect of the exploding on space, separate + pieces of a pattern MUST be separated with space, ie not " + 'word'/%i " but " 'word' / %i" + + EXAMPLE: + if (parse_command("spray car",environment(this_player()), + " 'spray' / 'paint' [paint] %i ",items)) + { + /* + If the pattern matched then items holds a return array as + described under 'destargs' %i above. + */ + } + + MUDLIB SUPPORT + + To make the efun useful it must have a certain support + from the mudlib, there is a set of functions that it needs + to call to get relevant information before it can parse in + a sensible manner. + + In earlier versions it used the normal id() lfun in the + LPC objects to find out if a given object was identified + by a certain string. This was highly inefficient as it + could result in hundreds or maybe thousands of calls when + very long commands were parsed. + + The new version relies on the LPC objects to give it three + lists of 'names'. + + 1 - The normal singular names. + 2 - The plural forms of the names. + 3 - The acknowledged adjectives of the object. + + These are fetched by calls to the functions: + + 1 - string *parse_command_id_list(); + 2 - string *parse_command_plural_id_list(); + 3 - string *parse_command_adjectiv_id_list(); + + The only really needed list is the first. If the second + does not exist than the efun will try to create one from + the singluar list. For grammatical reasons it does not + always succeed in a perfect way. This is especially true + + MudOS 5 Sep 1994 3 + + parse_command(3) LPC Library Functions parse_command(3) + + when the 'names' are not single words but phrases. + + The third is very nice to have because it makes constructs + like + + Apart from these functions that should exist in all + objects, and which are therefore best put in the base + mudlib object there is also a set of functions needed in + the master object. These are not absolutely necessary but + they give extra power to the efun. + + Basically these master object lfuns are there to give + default values for the lists of names fetched from each + object. + + The names in these lists are applicable to any and all + objects, the first three are identical to the lfuns in the + objects: + + string *parse_command_id_list() + - Would normally return: ({ "one", "thing" }) + + string *parse_command_plural_id_list() + - Would normally return: ({ "ones", "things", "them" }) + + string *parse_command_adjectiv_id_list() + - Would normally return ({ "iffish" }) + + The last two are the default list of the prepositions and + a single so called + string *parse_command_prepos_list() + - Would normally return: ({ "in", "on", "under" }) + + string parse_command_all_word() + - Would normally return: "all" + + MudOS 5 Sep 1994 4 + diff -c -r --new-file ds1.1/lib/doc/applies/parsing/parse_command_adjectiv_id_list ds2.1/lib/doc/applies/parsing/parse_command_adjectiv_id_list *** ds1.1/lib/doc/applies/parsing/parse_command_adjectiv_id_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parsing/parse_command_adjectiv_id_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_adjectiv_id_list - returns a list of names to the parser + + string array parse_command_adjectiv_id_list(); [sic] + + This routine is used to find out what adjectives the object responds to, and is + used by the parsing package and the parse_command() efun. In addition, + anything returned by the master object will work on ANY object. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/parsing/parse_command_id_list ds2.1/lib/doc/applies/parsing/parse_command_id_list *** ds1.1/lib/doc/applies/parsing/parse_command_id_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parsing/parse_command_id_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_id_list - returns a list of names to the parser + + string array parse_command_id_list(); + + This routine is used to find out what nouns the object responds to, and is + used by the parsing package and the parse_command() efun. In addition, + anything returned by the master object will work on ANY object. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/parsing/parse_command_plural_id_list ds2.1/lib/doc/applies/parsing/parse_command_plural_id_list *** ds1.1/lib/doc/applies/parsing/parse_command_plural_id_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/parsing/parse_command_plural_id_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + parse_command_plural_id_list - returns a list of names to the parser + + string array parse_command_plural_id_list(); + + This routine is used to find out what plural nouns the object responds to, + and is used by the parsing package and the parse_command() efun. In addition, + anything returned by the master object will work on ANY object. + + See also: + parse_command diff -c -r --new-file ds1.1/lib/doc/applies/preload ds2.1/lib/doc/applies/preload *** ds1.1/lib/doc/applies/preload Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/preload Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,15 ---- + preload - preload an object into memory + + void preload( string filename ); + + For each string in the array returned by epilog, the driver calls + preload(filename). Note that there is the equivalent of a catch() around + these calls at the driver level, so it is not neccessary for the mudlib + to worry about the sequence being terminated by an error. + + Typical behavoir is to use load_object() to attempt to load the file. + + See also: preload, , + load_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/privs_file ds2.1/lib/doc/applies/privs_file *** ds1.1/lib/doc/applies/privs_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/privs_file Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,15 ---- + privs_file - specifies the privs string to give to a newly created object + + string privs_file( string filename ); + + The privs_file() function is called in the master object when a new file + is created. The `filename' of the object is passed as the argument, and + the string that privs_file() returns is used as the new object's privs + string. + + The privs_file() functionality is only available if the driver is compiled + with the PRIVS option defined. + + See also: + query_privs + set_privs diff -c -r --new-file ds1.1/lib/doc/applies/process_input ds2.1/lib/doc/applies/process_input *** ds1.1/lib/doc/applies/process_input Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/process_input Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,19 ---- + process_input - inspect (and possibly modify) user input + + mixed process_input( string ); + + If process_input is present in the player object, then the MudOS driver + will send it a copy of each line the player types. If a string is returned, + that string is used as instead of the user input for further processing. + If a non-zero, non-string is returned, no further processing is done. + If zero is returned, processing continues with the original input. + Matching against add_actions is then done. + + Note: If NO_ADD_ACTION is defined, then there is no more processing to be + done after process_input. In this case, the return value is ignored, and + the mudlib is responsible for interpreting the string as a command (or other + user input for non-command based uses). + + See also: add_action + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/receive_message ds2.1/lib/doc/applies/receive_message *** ds1.1/lib/doc/applies/receive_message Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/receive_message Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,17 ---- + receive_message - provides the interface used by the message efun. + + void receive_message( mixed cl, mixed message ); + + The message() efun calls this method in the player object. The cl + parameter is typically used to indicate the class (say, tell, emote, + combat, room description, etc) of the message. The receive_message() + apply together with the message() efun can provide a good mechanism for + interfacing with a "smart" client. + + See also: + catch_tell, + message, + receive, + receive_snoop + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/receive_snoop ds2.1/lib/doc/applies/receive_snoop *** ds1.1/lib/doc/applies/receive_snoop Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/receive_snoop Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,14 ---- + receive_snoop - catch incoming snoop text + + void receive_snoop(string message); + + If RECEIVE_SNOOP is defined in options.h or local_options, + whenever a user is snooping another + user, all snoop text is sent to receive_snoop() in their user object. Inside + of this function, you can do as you wish with the text. A common activity + would be to receive() it. + + See also: + catch_tell, receive + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/reset ds2.1/lib/doc/applies/reset *** ds1.1/lib/doc/applies/reset Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/reset Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,13 ---- + reset - allows an object to do self-maintenance + + void reset(); + + After every reset interval (whose exact length is determined on + a mud by mud basis, but averages around every 2 hours), reset() + is called in every object that currently exists. If LAZY_RESETS + is defined in options.h in the driver, reset() will only be called + in objects when they are touched (near players), so unused objects + will not be loaded from the swap file to reset. + + See also: + set_reset diff -c -r --new-file ds1.1/lib/doc/applies/retrieve_ed_setup ds2.1/lib/doc/applies/retrieve_ed_setup *** ds1.1/lib/doc/applies/retrieve_ed_setup Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/retrieve_ed_setup Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,10 ---- + retrieve_ed_setup - retrieve a user's editor setup or configuration settings + + int retrieve_ed_setup( object user ); + + This master apply is called by the ed() efun to retrieve + a user's ed setup/configuration settings. This function + should return the setup (contained in an int). + + See also: + save_ed_setup diff -c -r --new-file ds1.1/lib/doc/applies/save_ed_setup ds2.1/lib/doc/applies/save_ed_setup *** ds1.1/lib/doc/applies/save_ed_setup Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/save_ed_setup Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,11 ---- + save_ed_setup - save a user's editor setup or configuration settings + + int save_ed_setup( object user, int config ); + + This master apply is called by the ed() efun to save + a user's ed setup/configuration settings (contained in + an int). This function should return an int for + success (1 or TRUE)/failure (0 or FALSE). + + Seel also: + retrieve_ed_setup diff -c -r --new-file ds1.1/lib/doc/applies/slow_shutdown ds2.1/lib/doc/applies/slow_shutdown *** ds1.1/lib/doc/applies/slow_shutdown Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/slow_shutdown Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,18 ---- + slow_shutdown - informs the mud that a slow shutdown is in progress + + int slow_shutdown( int minutes ); + + This master apply is called when the driver can't + allocate any more memory from the heap and had to + use its reserved memory block. This function can + only be called if the "reserved size" config file + setting was set. The minutes remaining to driver + shutdown is passed to this function. If this function + does ont exist, or returns zero, the driver shuts + down immediately. + + See also: + crash, + shutdown + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/telnet_suboption ds2.1/lib/doc/applies/telnet_suboption *** ds1.1/lib/doc/applies/telnet_suboption Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/telnet_suboption Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,17 ---- + telnet_suboption - process telnet suboptions + + void telnet_suboption( string buf ); + + This apply is called on the interactive object with the parameter given + by the SE telnet suboption, for mudlib defined processing. Note that + terminal type responses and window size responses are interpreted and + sent to terminal_type() and window_size() respectively instead of going + through telnet_suboption(). + + The first byte of the buffer is typically a type descriptor, + ie TELOPT_TTYPE. The next byte is a procession option, such + as TELQUAL_IS. Following this is the type dependent data. + + See also: terminal_type, window_size + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/terminal_type ds2.1/lib/doc/applies/terminal_type *** ds1.1/lib/doc/applies/terminal_type Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/terminal_type Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,10 ---- + terminal_type - inform the mudlib of the user's terminal type + + void terminal_type( string term ); + + This apply is called on the interactive object with term set to the + terminal type for the user, as reported by telnet negotiation. If the + user's client never responds (it's not telnet, for example) this will + never be called. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_bind ds2.1/lib/doc/applies/valid_bind *** ds1.1/lib/doc/applies/valid_bind Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_bind Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,12 ---- + valid_bind - determine if it is legal to bind a given function pointer to an object + + int valid_bind(object doer, object owner, object victim); + + This is called when 'doer' tries to use the bind() efun to bind a function + pointer owned by 'owner' to the object 'victim'. If this routine returns + zero, the operation is disallowed. + + See also: + bind + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_compile_to_c ds2.1/lib/doc/applies/valid_compile_to_c *** ds1.1/lib/doc/applies/valid_compile_to_c Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_compile_to_c Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,11 ---- + valid_compile_to_c - determine whether LPC->C compilation may take place + + int valid_compile_to_c(); + + valid_compile_to_c() is called when the generate_source() efun is used to + generate C files or to do runtime compilation of an object. One might + want to restrict the use of this since the process can be CPU intensive. + + See also: generate_source + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_hide ds2.1/lib/doc/applies/valid_hide *** ds1.1/lib/doc/applies/valid_hide Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_hide Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,15 ---- + valid_hide - allows or disallows objects to hide and see hidden objects + + int valid_hide( object ob ); + + Add valid_hide to master.c in order to allow objects to hide themselves, + or see other objects that have hidden themselves. When an object tries to + use the set_hide() efun to hide itself, valid_hide will be called with the + object that is wanting to hide as the sole parameter. It should return 1 + to allow it, or 0 to not allow it. The same call takes place when it needs + to be determined if a certain object should be able to see hidden objects. + + See also: + set_hide + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_link ds2.1/lib/doc/applies/valid_link *** ds1.1/lib/doc/applies/valid_link Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_link Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,13 ---- + valid_link - controls the use of the link efun + + int valid_link( string from, string to ); + + The driver calls valid_link(from, to) in the master object from inside the + link(from, to) efunction. If valid_link() returns 0, then the link() + will fail. If valid_link() returns 1, then the link will succeed if + rename() would succeed if called with the same arguments. + + See also: + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_object ds2.1/lib/doc/applies/valid_object *** ds1.1/lib/doc/applies/valid_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_object Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,14 ---- + valid_object - allows control over which objects can be loaded + + int valid_object( object obj ); + + After loading an object, the driver will call valid_object() with the newly + created object as its argument, in the master object. If the function + exists, and returns 0, then the object will be destructed and the efun that + caused it to load will error out. If it does not exist, or returns 1, then + loading will proceed as normal. This is called before the object has a + chance to execute any code, including create(), so not much should be + assumed about the object except that file_name(obj) is valid. + + See also: + valid_override diff -c -r --new-file ds1.1/lib/doc/applies/valid_override ds2.1/lib/doc/applies/valid_override *** ds1.1/lib/doc/applies/valid_override Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_override Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,48 ---- + valid_override - controls the use of efun:: + + int valid_override( string file, string efun_name, string mainfile ); + + File will be the actual file the call appears in; mainfile will be the file + being compiled (the two can differ due to #include) + + Add valid_override to master.c in order to control the use of the efun:: + prefix. The valid_override function in master.c will be called each + time the driver attempts to compile a function call that begins with + efun::. If valid_override returns 0, then that compile will fail. Thus + valid_override provides a way to modify the behavior of efuns that isn't + circumventable via the efun:: prefix (by having a simul_efun of the same + name as the efun to be modified and having valid_override disallow that + simul_efun from being overriden). + + If you wish to have the original 3.1.2 efun:: behavior, simply add + a line to master.c that looks like this: + + <pre> + int valid_override(string file, string efun) { return 1; } + </pre> + + Here is an example valid_override that is more restrictive: + <pre> + int + valid_override(string file, string name) + { + if (file == "/adm/obj/simul_efun") { + return 1; + } + if (name == "destruct") + return 0; + if (name == "shutdown") + return 0; + if (name == "snoop") + return 0; + if (name == "exec") + return 0; + return 1; + } + </pre> + + See also: + valid_object, + function_exists + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_read ds2.1/lib/doc/applies/valid_read *** ds1.1/lib/doc/applies/valid_read Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_read Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,14 ---- + valid_read - checks if a certain person has read permission on a file + + int valid_read( string file, object user, string func ); + + Every time an object tries to read a file, the driver calls valid_read + in the master object to check if the read should be allowed. The + arguments are the filename, the object making the read, and + the calling function name. If valid_read returns non-zero, the read is + allowed. + + See also: + valid_write + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_save_binary ds2.1/lib/doc/applies/valid_save_binary *** ds1.1/lib/doc/applies/valid_save_binary Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_save_binary Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,13 ---- + valid_save_binary - controls whether or not an object can save its loaded program + + int valid_save_binary( string file ); + + This routine is only used when BINARIES are enabled. + + When the driver is compiled with ALWAYS_SAVE_BINARIES, or an object uses + '#pragma save_binary', valid_save_binary is called with the program's filename. + If valid_save_binary returns 1, then the program will be saved to disk for + faster reloading, otherwise it will not be saved, and the next reload will + recompile as usual. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_seteuid ds2.1/lib/doc/applies/valid_seteuid *** ds1.1/lib/doc/applies/valid_seteuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_seteuid Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,18 ---- + valid_seteuid - secures the use of seteuid + + int valid_seteuid( object obj, string euid ); + + This routine is only used if PACKAGE_UIDS is defined. + + The driver calls valid_seteuid(ob, euid) in the master object from inside the + seteuid(euid) efunction. If valid_seteuid() returns 0, then the seteuid() + call will fail. If valid_seteuid() returns 1, then the seteuid() will + succeed. + + See also: + seteuid, + geteuid, + getuid, + export_uid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_shadow ds2.1/lib/doc/applies/valid_shadow *** ds1.1/lib/doc/applies/valid_shadow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_shadow Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,15 ---- + valid_shadow - controls which objects can be shadowed + + int valid_shadow( object ob ); + + When an object attempts to shadow `ob' (with the shadow() efun), valid_shadow + in the master object is called. One object parameter is passed, which is the + object that previous_object() is attempting to shadow. valid_shadow() should + return 0 if the shadow should not be permitted, in which case the shadow() call + will return 0 and fail. If valid_shadow() returns 1, the shadow is allowed. + + See also: + shadow, + query_shadowing + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_socket ds2.1/lib/doc/applies/valid_socket *** ds1.1/lib/doc/applies/valid_socket Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_socket Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,17 ---- + valid_socket - protects the socket efunctions + + int valid_socket( object caller, string function, mixed array info ); + + Each of the socket efunctions calls valid_socket() prior to executing. + If valid_socket returns 0, then the socket efunction fails. If + valid_socket returns 1, then the socket efunction attempts to succeed. + The first argument 'caller' is the object that called the socket efunction. + The second argument is the name of the socket efunction that is being + called (e.g. socket_write() or socket_bind()). The third argument is + an array of information. The first element of the array (when applicable) + is file descriptor being referenced. The second element of the array + is the owner of the socket (object). The third element of the array is + the address (string) of the remote end of the socket. The fourth element + of the array is the port number associated with the socket. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/valid_write ds2.1/lib/doc/applies/valid_write *** ds1.1/lib/doc/applies/valid_write Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/valid_write Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,14 ---- + valid_write - checks if a certain object has write permission on a file + + int valid_write( string file, object ob, string func ); + + Every time an object tries to write a file, the driver calls valid_write + in the master object to check if the write should be allowed. The + arguments are the filename, the object making the write, and + the calling function name (usually the name of the efun being used). + If valid_write returns non-zero, the write is allowed. + + See also: + valid_read + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/window_size ds2.1/lib/doc/applies/window_size *** ds1.1/lib/doc/applies/window_size Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/window_size Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,9 ---- + window_size - report the users window size + + void window_size(int width, int height); + + window_size() is called with the user's window size, as reported by telnet + negotiation. If the user's client never responds to the query, this is + never called. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/applies/write_prompt ds2.1/lib/doc/applies/write_prompt *** ds1.1/lib/doc/applies/write_prompt Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/applies/write_prompt Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,9 ---- + write_prompt - called when the parser wants a prompt to be written. + + void write_prompt(); + + If write_prompt is present in the player object, the driver will call it + whenever the default prompt would normally be printed. The driver will + not call write_prompt when the player is in input_to or ed. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/build/Armours ds2.1/lib/doc/build/Armours *** ds1.1/lib/doc/build/Armours Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Armours Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,180 ---- + Building Armours + The Nightmare IV LPC Library + written by Descartes of Borg 950430 + + Armour has changed quite a bit from the days of armour class. The + Nightmare IV LPC Library now uses damage types, which means armour that + is great against one attack may be pathetic against another. In fact, + in building armour, it is important that you keep in mind weaknesses. + Fortunately, armour is by default absolutely pathetic. If you go + making it awesome, chances are that it will not make it through the + approval process. This document is designed to get you started + building armour as well introduce you to the features available to + make unique and interesting armour. + + I. Basic Armour + You should be familiar with /doc/build/Items, as armour is just a + special type of item. It therefore has all of the features of regular + items. + + + + The basic armour looks like this: + + #include <lib.h> /* see this everywhere */ + #include <armour_types.h> /* a listing of armour types */ + #include <damage_types.h> /* a listing of damage types */ + + inherit LIB_ARMOUR; /* the armour inheritable */ + + static void create() { + armour::create(); /* call create() in armour.c */ + SetKeyName("rusty helm"); + SetId( ({ "helm", "rusty helm", "a rusty helm" }) ); + SetAdjectives( ({ "rusty" }) ); + SetShort("a rusty helm"); + SetLong("A rusty helmet which will be better than nothing on your head."); + SetMass(75); + SetValue(200); + SetDamagePoints(1000); + SetProtection(BLUNT, 4); /* SetProtection() sets the sort of */ + SetProtection(BLADE, 3); /* protection for a given damage type */ + SetProtection(KNIFE, 3); + SetArmourType(A_HELMET); /* set what kind of armour this is */ + } + + As you can see, there is very little that you have to do specific to + armour. The only armour specific call you MUST make is + SetArmourType(). Everything else is fluff. + + int SetArmourType(int type) + Armour types are found in /include/armour_types.h. The armour type + basically determines where the armour is worn. Each monster, + depending on its race, has for each limb a list of armour types which + may be worn on that limb. For example, most monsters have heads. + Some have two heads. You do not have to worry about this. They know + that they can wear anything that is A_HELMET on their heads. What if + you have something that may not be wearable on all monsters? Like, + for example, you have body armour which should only go on two armed + beings? See SetRestrictLimbs() later. It allows you to restrict + exactly which kinds of limbs can wear the armour. + + int SetProtection(int type, int amount); + Without this call, armour is nothing. Just something you wear. This + allows you to make clothes, which may protect against COLD, but do not + do a thing when struck with a sword. Protection is a number between 0 + and 100. Refer to approval documentation for details on what levels + are appropriate, as well as for information on mass and value levels. + + That's it for the basics! + + II. Advanced Function Calls + The Nightmare IV LPC Library armour object is fairly flexible for + allowing you to do interesting things with your armours. In this + section, you will learn about other function calls you can make to + customize your armour. + + string *SetRestrictLimbs(string *limbs); + Example: + SetRestrictLimbs( ({ "right arm", "left arm", "torso" }) ); + + For armours which can only be on certain body configurations, for + example regular armour (A_ARMOUR) should only be worn on people with + the same number of hands, this function allows you to restrict the + armour to being worn only on the limbs you name. If the person trying + to wear the armour does not have one of those limbs, any attempt to + wear fails. + + int SetFingers(int num); + Example: + SetFingers(5); + + Used for the glove types. If a person has more fingers on the limb on + which they are trying to wear a glove type than the glove has spaces + for, the wear fails. + + mixed SetWear(string | function val); + Examples: + SetWear("The cloak feels all yucky on you."); + SetWear( (: CheckArtrell :) ); + + Allows you to create a special message seen by the person wearing the + item when they wear it if you pass a string. On the other hand, if + you pass a function, it will call that function to see if the person + can wear the item. The function should be of the form: + int WearFunc(); + + For example: + + int CheckArtrell() { + if( (string)this_player()->GetRace() == "artrell" ) { + write("The rusty helm makes you feel safe."); + say((string)this_player()->GetName() + " wears a rusty helm."); + return 1; + } + else { + write("You cannot wear that you bum!"); + return 1; + } + } + + III. Function Overrides + The only function of interest that you might want to override is a + function called eventReceiveDamage(). This function is called every + time the armour is hit to see how much of the damage it absorbs. It + looks like this: + + int eventReceiveDamage(int type, int strength, int unused, mixed limbs); + + This function is called by combat to determine how much damage the + armour absorbs for a given bit of damage being done. It thus should + return how much damage it takes. + + You should always at some point call item::eventReceiveDamage() so + that it can do its processing. You do not want to call it, however, + until you determine how much damage you are absorbing unnaturally. + Here is a sample one for an armour that does extra protection for fighters: + + int eventReceiveDamage(int type, int strength, int blah, mixed limbs) { + object who_is_wearing; + int x; + + if( !(who_is_wearing = environment()) ) /* eek! no one wearing */ + return 0; + if( (int)who_is_wearing->ClassMember("fighter") ) /* reduce strength */ + x = strength - random(5); + if( x < 1 ) return strength; /* protect against all the damage */ + return armour::eventReceiveDamage(type, x, blah, limbs); + } + + Keep in mind what eventReceiveDamage() in armour.c is doing. First, + it is modifying the strength of the blow based on the protections you + set with SetProtection(). Then, it is having the armour take damage + based on how much it absorbed. So you need to call + eventReceiveDamage() in armour at the point where you have a value you + want the armour to do its normal stuff with. In the example above, we + wanted to magically protect fighters against a random(5) points of + damage without having the armour take any damage for that. Then if + there is still strength left in the blow, the armour does its normal + protection. + + What else can you do with this? Imagine an armour that turns all cold + damage back on the attacker? + + int eventReceiveDamage(int type, int strength, int unused, mixed limbs) { + object who_wearing, enemy; + + enemy = (object)(who_wearing = previous_object())->GetCurrentEnemy(); + if( !enemy || !(type & COLD) ) + return armour::eventReceiveDamage(type, strength, unused, limbs); + limbs = enemy->GetTargetLimb(0); + message("environment", "Your anti-cold throws the frost in your " + "enemy's face!", who_wearing); + message("environment", "Your cold attack is turned back upon you!", + enemy); + enemy->eventReceiveDamage(COLD, strength, unused, limbs); + return strength; /* we absorb all of the strength but take no damage */ + } + + Descartes of Borg + borg@imaginary.com diff -c -r --new-file ds1.1/lib/doc/build/Barkeeps ds2.1/lib/doc/build/Barkeeps *** ds1.1/lib/doc/build/Barkeeps Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Barkeeps Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,67 ---- + Building Food and Drink Sellers + The Nightmare IV LPC Library + written by Descartes of Borg 950528 + + This document details the building of barkeeps, waiters, and other + such people who sell food and drink. Barkeeps are NPC's, and + therefore everythign which applies to NPC's applies to barkeeps. + + To build a barkeep, you should inherit LIB_BARKEEP. + + Beyond the functions specific to NPC's barkeeps also make use of the + following functions: + + mapping SetMenuItems(mapping menu); + mapping AddMenuItem(string item, string file); + mapping RemoveMenuItem(string item); + mapping GetMenuItems(); + string SetLocalCurrency(string curr); + + When building a barkeep, you must add some mechanism in the room in + which the barkeep is placed for people to view a list of things for + sale. + + ***** + mapping SetMenuItems(mapping menu); + ***** + + Example: SetMenuItems( ([ "coffee" : "/realms/descartes/coffee" ]) ); + + Sets which menu items are found in which file. This is a mapping with + the name of the item as a key and the file in which it is located as + the value. + + ***** + mapping AddMenuItem(string item, string file); + ***** + + Example: AddMenuItem("lobster", "/realms/descartes/lobster"); + + Adds one menu item at a time to the list of menu items. + + ***** + mapping RemoveMenuItem(string item); + ***** + + Example: RemoveMenuItem("coffee"); + + Removes the named item from the menu. + + ***** + mapping GetMenuItems(); + ***** + + Returns all the menu items for this barkeep. Useful in building your + menu list. + + ***** + string SetLocalCurrency(string curr); + ***** + + Example: SetLocalCurrency("khucha"); + + Sets the currency in which the barkeep does business. + + + + diff -c -r --new-file ds1.1/lib/doc/build/Climates ds2.1/lib/doc/build/Climates *** ds1.1/lib/doc/build/Climates Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Climates Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,6 ---- + indoors + temperate + arid + arctic + tropical + sub-tropical diff -c -r --new-file ds1.1/lib/doc/build/Doors ds2.1/lib/doc/build/Doors *** ds1.1/lib/doc/build/Doors Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Doors Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,262 ---- + Creating Doors between Two Rooms + The Nightmare IV LPC Library + created by Descartes of Borg 950419 + + This document describes how to build door-type objects which link two + rooms. These door-type objects do not need to be doors, but in fact + can be windows or boulders or any other such object. The Nightmare IV + LPC Library door object, unlike the old way of doing doors, is an + object separate from the rooms it connects. In other words, in order + to build a door, you have three objects (just as you would visualize): + two rooms and a door. + + The door object is /lib/door.c. To inherit it, #include <lib.h> and + inherit LIB_DOOR;. An example door may be found in + /domains/Examples/etc/door.c as well as the rooms + /domains/Examples/room/doorroom1.c and /domains/Examples/room/doorroom2.c. + + Setting up the door object + The first thing you must do is create the door object. You must + visualize this door object just like a door connecting two rooms in + real life. You have a room on each side with a single door with two + sides. Technically, a door object may have any number of sides. + Practically speaking, most people using this object will be using it + as a door, which means it will have two sides. + + To create a door object, you simply describe each side of the door. + The easiest way to do this is through the SetSide() function. + + mapping SetSide(string side, mapping mp); + + Example: + + SetSide("east", ([ "id" : "red door", "short" : "a red door", + "long" : "A freshly painted red door.", + "lockable" : 0 ]) ); + + The name of the side is simply the exit used by the room which sees + that side. For example, if in one room the door is at the east exit, + then the side is identified as east. The mapping consists of the + following data: + + "id" + What a person on that side calls the door. For example, you can have a + door blue on one side and red on the other. On one side, you go east + to go through the door, and from that room the door appears red. The + id for that side might be "red door". The id for the other side might + be "blue door". + + "short" + The short description for the door as seen from the side in question. + This can be a function or a string. + + "long" + The long description for the door as seen from the side in question. + Whether the door is open or not will be added to the long if the long + is a string. This can be either a string or function. If it is a + function, you must specify whether the door is open or close on your + own. + + "lockable" + 0 if the door cannot be locked (and unlocked) from that side, 1 if it + can. + + "keys" + An array of id's of objects which can be used to unlock it if it is + lockable. Lockable doors do not need keys. + + II. Setting up the rooms + After you have called SetItems() and SetExits() in the room + (remembering to set the exit for the exit with the door), call the + function SetDoor(). + + string SetDoor(string dir, string doorfile); + + Example: SetDoor("east", "/realms/descartes/doors/red_door"); + + Sets the exit named to be blocked by a door object when that door + object is closed. + + This is all you need to do in the room. Note that the exit name + corresponds to the side name mentioned in the door. + + III. Advanced Door Stuff + At this point, you should know how to do the minimum stuff to build a + door. This section goes into detail about door functions and how you + can do advanced things with doors by manipulating door events. This + section has two parts, door data functions and door events. + + a. Door Data Functions + + ***** + SetSide() + ***** + mapping SetSide(string side, mapping mp); + + As described above. + + ***** + SetClosed() + ***** + static int SetClosed(int x) + + Example: SetClosed(1); + + This function can only be called from inside the door object. + Generally you use it to set the initial state of the door. If you + want to close the door at any other time, or to close it from another + object, use eventClose() or eventOpen(). + + ***** + SetLocked() + ***** + + static int SetLocked(int x) + + Example: SetLocked(1); + + Like SetClosed(), this function should only be used from create() + inside the door object to set the initial state of the door. At other + times, use eventLock() or eventUnlock(). + + ***** + SetLockable() + ***** + + int SetLockable(string side, int x) + + Example: SetLockable("east", 1); + + Sets a side as being able to be locked or unlocked. Since it is done + by sides, this means you can have one side not be lockable with the + other side being lockable. The first argument is the side being set + lockable or not lockable, the second argument is 1 for lockable and 0 + for not lockable. + + ***** + SetId() + ***** + + string SetId(string side, string id) + + Example: SetId("west", "blue door"); + + This is not like your traditional SetId() function. Instead, it sets + a single way of identifying the door from a given side. It is what + the player might use to open the door or look at it. + + ***** + SetShort() + ***** + + mixed SetShort(string side, string | function desc) + + Examples: + SetShort("north", "a red door"); + SetShort("west", (: GetWestShort :) ); + + Sets the short description for a given side of a door. If the second + argument is a function, it gets passed as an argument the name of the + side for which the function serves as a description. That function + should return a string. For the above: + + string GetWestShort(string dir) { + if( query_night() ) return "a shadowy door"; + else return "a red door"; + } + + ***** + SetLong() + ***** + + mixed SetLong(string side, string | function desc) + + Examples: + SetLong("south", "An old, dusty door covered in cobwebs."); + SetLong("east", (: GetEastLong :)) + + This works much like the SetShort() function, except it handles the + long description. It is important to note that if the second argument + is a string, that the state of the door will be added onto the long + description automatically. In other words "It is open." will appear + as the second line. This will *not* be done if you use a function for + your long description. + + ***** + SetKeys() + ***** + + string *SetKeys(string side, string *keys) + + Example: SetKeys("east", ({ "skeleton key", "special key" })); + + Builds an array of id's which can be used to unlock the door if it is + lockable from this side. In other words, a person can only unlock the + door if that person has an object which has one of the id's you + specify for its id. + + b. Events + + ***** + eventOpen() + ***** + + varargs int eventOpen(object by, object agent) + + Examples: + + "/realms/descartes/etc/red_door"->eventOpen(this_object()); + + int eventOpen(object by, object agent) { + if( query_night() ) return 0; /* Can't open it at night */ + else return door::eventOpen(by, agent); + } + + The function that actually allows the door to be opened externally. + It returns 1 if the door is successfully opened. It returns 0 if it + fails. The first argument is the room object from which the door is + being opened. The second argument, which is optional, is the living + thing responsible for opening the door. + + The first example above is an example of what you might do from + reset() inside a room in order to have the door start open at every + reset. + + The second example above is an example of how you might conditionally + prevent the door from opening by overriding the Open event. In this + case, if it is night, you cannot open this door. If it is day, you + can. + + ***** + eventClose() + ***** + + varargs int eventClose(object by, object agent) + + Example: See eventOpen() + + This function works just like eventOpen(), except it does the closing + of the door. + + ***** + eventLock() + ***** + + varargs int eventLock(object by, object agent) + + Example: see eventOpen() + + This function works just like eventOpen(), except that it gets called + for locking the door. + + ***** + eventUnlock() + ***** + + varargs int eventUnlock(object by, object agent) + + Example: See eventOpen() + + This function works just like eventOpen(), except that it gets called + for unlocking the door. + diff -c -r --new-file ds1.1/lib/doc/build/Introduction ds2.1/lib/doc/build/Introduction *** ds1.1/lib/doc/build/Introduction Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Introduction Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,146 ---- + Introduction to Building Nightmare Objects + Nightmare IV Object Library + written by Descartes of Borg 951204 + + If you are anything like I was when I became a creator for the first + time, then your knowledge of computers consists of how to write a + paper using WordPerfect and how to play the games you like to play. + It probably seems like a long distance between that and actually + writing programs to run on a computer. And the truth is, many years + ago it was. + + Programming a computer is no longer really programming. It is more + like playing with Legos. Whereas you used to feed into a computer + step by step instructions on how the program is supposed to work, + today instead you fit objects together like pieces of a puzzle and + define their basic characteristics. The object library handles the + rest. + + Of course, that begs the question, what is an object? + + It is easiest to understand the concept if you get out of the computer + mindset. Just think about things like you do in every day life. + Objects simply are things. Your house is an object, your car is an + object, your floor is an object, your cat is an object, and you are an + object. Programming for an LPMud is simply about defining what + objects exist in the world. + + What distinguishes you from your cat? What distinguishes your cat + from your neighbour's cat? Each object has two defining pieces, its + attributes and its behaviour. An attribute is simply something that + is true of the object, for example, your cat has green eyes, while + your neighbours has blue. Things such as name, eye colour, fur + length, tail length, mass, intelligence, etc. are all attributes. In + building on muds, you will often hear attributes referred to as global + variables. + + The other part of an object is its behaviour. In the real world, + things happen to objects, and objects react. Your cat sees a bird. + Seeing the bird causes the cat to salivate. The cat in turn hunts the + bird. The chain of events really goes on and on with no identifiable + beginning or end, except in the way you describe the event. For + example, you could take the cat seeing the bird as being caused by the + bird landing, which was caused by its migration south, which was + caused by the change of seasons... + + The bottom line is that the world is full of objects which behave in + response to events according to their attributes and built-in nature. + Building objects on a mud therefore is about setting the attributes + for specific objects and defining they way they react to certain + events. Fortunately, the LPC language has built-in mechanism to make + this easy. It is called inheritance. + + Going back to the cat example, let's say you were going to build a + cat. You could go and rewrite every piece of behaviour common to your + first cat and your neghbour's cat. If you were going to build ten + cats, that would get tedious. LPC allows you to build a generic cat, + then customize an instance of that generic class and make it your cat. + + The Nightmare Object Library is what its name implies, a library of + objects that object-oriented terminology refers to as "abstract + classes". An abstract class is a type of object you never see running + around the mud. Instead, it is a building block used in the objects + you see running around the mud. In other words, the object library + builds the concept of cat, and you use this to build individual cats. + Another analogy is that of the object library being like a Lego set. + You take the pieces it gives you to build specific objects. + + In building an area, you know understand your task is to build the + objects which make up that area. Building an object simply means + using the abstract classes the object library gives you to create + specific instances of those abstract classes. You do this by defining + the specific attributes of the new objects, and defining new + behaviours. + + You have probably heard me refer to the terms behaviour and event + interchangeably. In philosophy, they are not interchangeable. A + behaviour is a type of event which is defined as being caused by + something that meant to cause the event. In other words, the cat + chasing the bird is behaviour, while the cat seeing the bird is simply + an event. Both are considered events. With respect to objects, you + are really defining events, since some events are actually + unintentional responses to other events. The Nightmare Object Library + therefore refers to what you define in objects as events. + + Writing an event in LPC is nothing more that providing step by step + instructions for what happens when a given event occurs. The LPC term + for an event is a function (sometimes you will hear people refer to + functions as methods). The Nightmare Object Library uses four types of + events: + + #1 MudOS initiated events, sometimes called an "apply" + The names of these events are all lower case. The most common apply + is the create() event. It is caused by the creation of the object. + + #2 Attribute manipulation events + These are the SetXXX() and GetXXX() events. They exist basically to + allow other objects to find out about an object's attributes, or to do + initial setup for an object's attributes. + + #3 Modal events + These are the CanXXX() events. They get called often just prior to a + behaviour type of an event. For example, I am trying to leave a room, + so my leave behaviour asks the room if I can leave. This would be + CanLeave() in the room. If CanLeave() says I can leave, then the + leave event is triggered in the room. + + #4 True events + A true event is identified by eventXXX(). These type of events are + the meat of what is happening in the game. Any given true event is + generally in turn triggered by some other true event. The chain + generally can be traced as starting with a player or NPC command at + some point. + + There are also two other types of functions which are not really + events, but instead simple routines that perform complex operations, + like the absolute_value() function. These functions belong to no + particular object since they are not really events. Instead any + object in the game may refer to them. You will hear them referred to + sefuns (simul efuns) and efuns respectively. + + So, an object in the Nightmare Object Library consists of all of these + events. That sounds like you have a lot to do? Not really. The + object library itself defines almost all of the events needed for any + particular object. Most often, you will be defining only one event + for any object, the creation event (create()). + + The event create() is triggered by MudOS for every single object when + it is first created. This is therefore the ideal place for defining + what the attributes are for an object, so your create() generally ends + up being a series of SetXXX() calls. In addition, if you add any + attributes, you will want to give them values in create(). + + Take for example an NPC. Any NPC you build will have to have a name. + Thus, when it gets created, you want to be sure to set its name. You + do this through the SetKeyName() event. + + The documents in this directory primarily describe for you what + SetXXX() functions exist in objects to allow you to define your own + unique objects. Once you are feeling comfortable with building simple + objects that only have create() behaviours, you can then start adding + other behaviours to objects. For example, one type of behaviour you + can add to some rooms is to respond to someone digging in the room. + You thus define CanDig() and eventDig() events in addition to your + create() event. In the event, whatever events you end up defining, + they end up being nothing more than modifying attributes of the object + in question, or causing events in other objects. diff -c -r --new-file ds1.1/lib/doc/build/Items ds2.1/lib/doc/build/Items *** ds1.1/lib/doc/build/Items Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Items Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,367 ---- + Building Any Item + The Nightmare IV LPC Library + written by Descartes of Borg 950430 + + Each object you build has a certain common make-up no matter what type + of object it is. This is because all of your objects actually are + based upon the same object, the object called /lib/object.c. That + object contains functions such as SetShort() and SetLong() which you + use in almost every single object you will build. This document + details how to set up any possible object you will use. The only + exceptions will be for rooms, which do not have key names or id's. + + Beyond that, most of the every day objects you will code like armours, + weapons, drinks, foods, etc. all derive from a common object called + /lib/item.c. This document attempts to detail what is involved in + building any object on the MUD through /lib/item.c and its ancestor + /lib/object.c. + + This document is in three sections + + I. List of Mandatory Function Calls + II. Basic Functions + III. Extras + IV. Events + + ** *************** List of Mandatory Function Calls ************** ** + + SetKeyName("red bag"); + SetId( ({ "bag", "red bag" }) ); + SetAdjectives( ({ "red" }) ); + SetShort("a red bag"); + SetLong("A small red bag with no distinguishing marks."); + SetMass(90); + SetValue(50); + SetVendorType(VT_BAG); + + You also need to include vendor_types.h. + + ** *************** Basic Functions *************** ** + + ***** + SetKeyName() + ***** + + string SetKeyName(string key_name); + + Example: SetKeyName("red bag"); + + Notes: + Mandatory for all objects except rooms. + Not used for rooms. + + The key name is the central name by which the object is referred to in + sentences where no article is required. For example, the sentence + "You pick up your red bag" makes use of the key name to complete the + sentence. This is much like the short description, except the short + description will include an article. For this object, SetShort("a red + bag") would be used. + + ***** + SetId() + ***** + + string *SetId(string *id); + + Example: SetId( ({ "bag", "red bag" }) ); + + Notes: + Mandatory for all objects except rooms. + Not used in rooms. + Must be all lower case. + + The id is an array of strings by which the object may be referred to by a + player. For example, if the player wants to get this bag, the player + can type "get bag" or "get red bag". The id is used purely for + identification purposes, so if you have something you need to sneak in + a unique way of identifying it, you may add an id only you know about. + + ***** + SetAdjectives() + ***** + + string *SetAdjectives(string *adjs); + + Example: SetAdjectives( ({ "red" }) ); + + Notes: + Planned for future use in Zork style command parsing. + Not used in rooms. + + The adjectives are descriptive terms used to describe the object. + This is not currently being used, however, it will be part of the new + style command parsing we will be building. This will allow the player + to type things like "get the red one" and pick up the red bag. Even + though it is not used, it is requested you place it in your objects to + make upgrading down the road a simpler task. + + ***** + SetShort() + ***** + + string SetShort(string description | function desc_func); + + Examples: + SetShort("a red bag"); + SetShort((: DescribeBag :)); + + The short description is a brief description of the object. Only + names and proper nouns should be capitalized, the rest should be lower + case, as if it were appearing in the middle of a sentence. In rooms, + the player sees the short description when in brief mode and when they + glance at the room. For objects, the player sees the short when it is + described in the room or in their inventory. + + If you pass a function instead of a string, then that function is used + to create the description. You can use this to do something like make + the object change its short description depending on who is looking at + it. The function that you build should therefore return a string + that will be used as the short description. For example... + + string DescribeBag() { + if( query_night() ) return "a bag"; + else return "a red bag"; + } + + ***** + SetLong() + ***** + + string SetLong(string description | function desc_func); + + Examples: + SetLong("A red bag with no markings on it whatsoever."); + SetLong((: BagLong :)); + + Creates a verbose way to present the object to the player. You should + be much more descriptive than I have been in the example. Being a + text game, descriptions are 90% of what make the game. The more + creative you are with your descriptions, the more interesting the game + is to players. The long description of a room is seen by players in + verbose mode and when the player uses the "look" command. For + objects, the long description is seen when the player looks at the + object. Functions work in exactly the same fashion as short + functions. + + ***** + SetMass() + ***** + + int SetMass(int mass); + + Example: SetMass(100); + + Notes: + Mandatory for all visible objects. + Not needed for non-tangible objects and rooms. + + Sets the mass for the object. In conjunction with the gravity of the + room it is in, this works to determine the weight of the object. + + ***** + SetValue() + ***** + + int SetValue(int value); + + Example: SetValue(50); + + Notes: + Mandatory for all sellable objects. + Not used in rooms. + + Sets the base economic value of an object. This has no meaning in any + currencies, and in fact the actual value in any given currency may + vary. + + ***** + SetVendorType() + ***** + + int SetVendorType(int vt); + + Example: SetVendorType(VT_BAG); + + Note: + Mandatory for all objects except rooms. + Preset to VT_ARMOUR for objects which inherit LIB_ARMOUR. + Preset to VT_TREASURE for objects which inherit LIB_ITEM. + Preset to VT_LIGHT for objects which inherit LIB_LIGHT. + Not valid for room objects. + Values are found in /include/vendor_types.h. + + You must do: + #include <vendor_types.h> + to use the VT_* macros (i.e. VT_ARMOUR, VT_TREASURE, VT_WEAPON). + + The vendor type determines which shops will buy the item. For + example, things with VT_BAG as the vendor type can be bought and sold + in bag stores. For items which cross the line, for example a flaming + sword, you can combine vendor types in the following manner: + SetVendorType(VT_WEAPON | VT_LIGHT); + + ***** + SetDamagePoints() + ***** + + int SetDamagePoints(int pts); + + Example: SetDamagePoints(500) + + Sets the amount of damage an object can take before descreasing in + value. With armours and weapons, damage is taken quite often. Damage + is more rare with other kinds of objects. With this example object + which has 500 damage points, whenever 500 points has been done to it, + its value is cut in half and eventDeteriorate() is called for the + object. See the events section on using eventDeteriorate(). The + points are then reset to 500 and damage is done from that. + + ** *************** Extras *************** ** + + ***** + SetProperty() + ***** + + mixed SetProperty(string property, mixed value); + + Example: SetProperty("no pick", 1); + + Allows you to store information in an object which may not have been + intended by the designer of the object, or which is fleeting in + nature. See /doc/build/Properties for a list of common properties. + ***** + SetProperties() + ***** + + mapping SetProperties(mapping props); + + Example: SetProperties( ([ "light" : 1, "no attack" : 1 ]) ); + + Allows you to set any properties you want all in one shot. + + ***** + SetDestroyOnSell() + ***** + + int SetDestroyOnSell(int true_or_false); + + Example: SetDestroyOnSell(1); + + For mundane objects, or objects which should not be resold, allows you + to set it so that the object gets destroyed when sold instead of + allowing it to be resold. + + ***** + SetPreventGet() + ***** + + mixed SetPreventGet(mixed val); + + Examples: + SetPreventGet("You cannot get that!"); + SetPreventGet( (: check_get :) ); + + Allows you to make an object un-gettable by a player. If you pass a + string, the player will see that string any time they try to get the + item. If you pass a function, that function will be called to see if + you want to allow the get. Your function gets the person trying to get + the object as an argument: + + int check_get(object who) { + if( (int)who->GetRave() == "ogre" ) { + message("my_action", "Ogres cannot get this thing!", who); + return 0; + } + else return 1; + } + + ***** + SetPreventPut() + ***** + + mixed SetPreventPut(mixed val); + + Examples: + SetPreventPut("You cannot put that in there!"); + SetPreventPut( (: check_put :) ); + + The same as SetPreventGet(), except this is used when the object is + being put into another object. + + ***** + SetPreventDrop() + ***** + + mixed SetPreventDrop(mixed val); + + Examples: + SetPreventDrop("You cannot drop that!"); + SetPreventDrop( (: check_drop :) ); + + The same as SetPreventGet(), except this is used when a player tries + to drop the object. + + + ** *************** General Events ************** ** + + ***** + eventDeteriorate() + ***** + + void eventDeteriorate(int type); + + Example: ob->eventDeteriorate(COLD); + + Notes: + Damage types can be found in /include/damage_types.h + + This function gets called periodically in objects whenever they wear + down a bit. The type passed to the function is the type of damage + which triggered the deterioration. + + ***** + eventMove() + ***** + + int eventMove(mixed dest); + + Example: + ob->eventMove(this_player()); + ob->eventMove("/domains/Praxis/square"); + + The eventMove event is called in an object when it is being moved from + one place to the next. You can either pass it the file name of a room + to which it should be moved or an object into which it should be + moved. It will return true if the object gets moved, false if it + cannot move for some reason. For objects which are being dropped, + gotten, or put, it is generally a good idea to check CanDrop(), + CanClose(), or CanGet() for the object in question since eventMove() + does not know the context of the move and therefore will allow a drop + since it does not check CanDrop(). + + ***** + eventReceiveDamage() + ***** + + varargs int eventReceiveDamage(int type, int amount, int unused, mixed limbs); + + Example: ob->eventReceiveDamage(BLUNT, 30, 0, "right hand"); + + This function gets called in an object whenever any damage is done to + it. Most frequently this gets called in monsters and armour. In + armour you can use it to modify the amount of damage which gets done. + The return value of this function is the amount of damage done to the + object. For example, if you have a piece of armour that absorbs 5 of + the 30 points listed above, then you return 5. + + NOTE: + For monsters there is an extra arg at the front called + agent. The agent is the being responsible for doing + the damage. It may be zero if something like the weather + is causing the damage. It looks like: + + varargs int eventReceiveDamage(object agent, int type, int strength, + int internal, mixed limbs); + + For more detailed information, see /doc/build/NPC. + diff -c -r --new-file ds1.1/lib/doc/build/Meals ds2.1/lib/doc/build/Meals *** ds1.1/lib/doc/build/Meals Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Meals Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,150 ---- + Building Food and Drink Objects + The Nightmare IV LPC Library + written by Descartes of Borg 950603 + + This document details the creation of food and drinks using the + Nightmare LPC Library. The creation of barkeeper objects requires you + to be able to build these objects, so make sure you understand what is + going on in here before moving on to barkeepers. + + To create food or drink, you inherit from the standard meal object + /lib/meal.c For example: + + #include <lib.h> + + inherit LIB_MEAL; + + You have access to the same functions you have in generic items when + you build food and drinks. In particular, you should be sure to call + the following: + + SetKeyName() + SetId() + SetShort() + SetLong() + SetMass() + + Note that SetValue() does NOTHING for food and drinks. Value is + automatically determined by the strength of the item. + + The following function calls are specific to "meal" objects: + + int SetMealType(int types); + int SetStrength(int strength); + + mixed *SetMealMessages(function f); + OR + mixed *SetMealmessages(string mymsg, string othermsg); + + string SetEmptyName(string str); + string SetEmptyShort(string str); + string SetEmptyLong(string str); + string SetEmptyItem(string str); + + You must call SetMealType(), SetStrength(), and SetMealMessages(). + If you call SetEmptyItem(), you do not need to call the functions + SetEmptyName(), SetEmptyShort(), SetEmptyLong(). On the other hand, + if you do not call SetEmptyItem(), you do need to set the other three. + + ***** + int SetMealType(int types) + ***** + + Example: SetMealType(MEAL_FOOD); + + For meal objects, you must do: + + #include <meal_types.h> + + This includes all od the definitions for the meal types in + /include/meal_types.h into your food or drink. You need these + definitions when setting what type of meal object this is. The types + are: + + MEAL_FOOD + MEAL_DRINK + MEAL_CAFFEINE + MEAL_ALCOHOL + MEAL_POISON + + In general, almost anything you create will be at least either + MEAL_FOOD or MEAL_DRINK. You can add onto it using the | operator. + For example, to make an alcoholic drink: + + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + + This makes something a drink and an alcoholic drink. You want to + stick poison in it? + + SetMealType(MEAL_DRINK | MEAL_ALCOHOL | MEAL_POISON); + + ***** + int SetStrength(int x) + ***** + + Example: SetStrength(20); + + This sets how strong your food or drink is. It affects things like + which people can drink or eat it and how much the drink or food costs. + Refer to balance documents to see what is good. + + ***** + varargs mixed *SetMealMessages(function|string, string) + ***** + + Examples: + SetMealMessages((: call_other(find_object("/some/object"),"drink") :)); + SetMealmessages("You drink your beer.", "$N drinks $P beer."); + + You can pass a single argument, which is a function to be called. + This function will be called after the person has drank or eaten the + meal. It gives you a chance to do some bizarre messaging and such. + + If you pass two strings, the first string is used as a message to send + to the player doing the drinking, and the second is what everyone else + sees. To make the message versatile, you can put in the following + place holders: + + $N the name of the drinker/eater + $P his/her/its + + For example: + $N drinks $P beer. + might resolve to: + Descartes drinks his beer. + + ***** + string SetEmptyName(string str) + ***** + + Example: SetEmptyName("bottle"); + + Sets an id from the empty container of drinks. This need not be set + for food. + + ***** + string SetEmptyShort(string str) + ***** + + Example: SetEmptyShort("an empty bottle") + + Sets what the short description of the empty container is for anything + that is of type MEAL_DRINK. + + ***** + string SetEmptyLong(string str) + ***** + + Example: SetEmptyLong("A brown bottle that used to contain beer."); + + Sets the long description for the empty container for drink objects. + + ***** + string SetEmptyItem(string str) + ***** + + Example: SetEmptyItem("/domains/Praxis/etc/empty_bottle") + + Instead of cloning a generic empty object and setting the other empty + functions, you can create a special empty container which gets given + to the player after they drink a drink object. Not relevant to food. diff -c -r --new-file ds1.1/lib/doc/build/NPC ds2.1/lib/doc/build/NPC *** ds1.1/lib/doc/build/NPC Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/NPC Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,284 ---- + Building Non-Player Characters + The Nightmare IV Object Library + written by Descartes of Borg 951201 + + This document outlines the creation of non-player characters (NPC's). + On other muds, NPC's are sometimes referred to as monsters. Like the + rooms document, this document is divided up into two sections: basic + NPC building and complex NPC building. NPC's are living things which + inherit all the behaviours of living things. Documentation on living + specific functionality may be found in /doc/build/Livings. + + ************************************************ + Part 1: Basic NPC Building + ************************************************ + + ***** + I. The simplest NPC + ***** + + #include <lib.h> + + inherit LIB_NPC; + + static void create() { + npc::create(); + SetKeyName("praxis peasant"); + SetId( ({ "peasant", "praxis peasant" }) ); + SetShort("a local peasant"); + SetLong("Dirty and totally disheveled, this poor inhabitant of Praxis " + "still somehow maintains an air of dignity that nothing can " + "break."); + SetLevel(1); + SetRace("elf"); + SetClass("fighter"); + SetGender("male"); + } + + There are two things you should note. The first is that an NPC is + also a general object, meaning that you have available to you all the + things you can do with general objects, like setting descriptions and + ID's. The second is that a basic NPC does not require a heck of a lot + more. I will cover the NPC specific functions here. + + SetLevel(1) + SetRace("elf") + SetClass("fighter") + Level, race, and class are the three most important settings in any + NPC. Together they determine how powerful the NPC is. You are + absolutely required to set a level and a race. For those who + absolutely do not want to give the NPC a class, you do not have to. + But, you must instead manually set the NPC's skill levels, which is + described in the second part of this document. In general, however, + you always want to set the class. + + Together, the class and race and level determine which skills and + stats are considered important for the monster, and how good at those + skills and stats the monster is. The order in which you call these + functions is irrelevant, as everything is recalculated any time one of + the above changes. + + Also, note that SetRace() may only be called with a race listed in the + mraces command with simple NPC's. If you wish to build an NPC with a + unique race, you need to do some limb manipulation, which is described + in the advanced section. + + SetGender("male") + While not required, you will normally want to give an NPC a gender. + The default is neutral. However, in this world, very little is + neuter. Your choices for this function are male, female, and neuter. + + ***** + II. Other NPC Configuration Functions + ***** + + Function: int SetMorality(int amount); + Example: SetMorality(100); + + This is a number between -2000 and 2000 which determines the morality + of an individual with respect to good and evil. -2000 is absolute + evil, and 2000 is absolute good. The actions of players determine + their morality, and often those actions are relative to a target. + Thus killing an evil being can be considered good, while killing a bad + one evil. + + Function: int SetUnique(int x); + Example: SetUnique(1) + + Marks the NPC as a unique monster. This allows the room which clones + your NPC to use the negative values to SetInventory() (see + /doc/build/Rooms) to make sure the NPC only gets cloned every few + days. + + ************************************************ + Part 2: Advanced NPC Building + ************************************************ + + ***** + I. Functions + ***** + + You may use these functions to make your NPC's a bit more interesting + than the simple variety. + + Function: void SetAction(int chance, mixed val); + Examples: SetAction(5, (: DoSomething :)); + SetAction(5, ({ "!smile", "!frown" })); + SetAction(5, ({ "The peasant looks unhappy." })); + + Sets something to randomly happen every few heart beats while the NPC + is not in combat. In the above examples, the NPC has a 5% chance each + heart beat of performing the action you provided with the second + argument. The action can be a call to a function, a list of potential + commands, or a list of strings to be echoed to the room. + + If you pass a function, that function will be called each time an + action is supposed to occur. If you pass a list of strings, one of + those strings will be randomly chosen as the target action for this + heart beat. If the chosen string begins with a !, it is treated as a + command. Otherwise, it is simply echoed to the room. Note that you + can mix commands and echo strings. + + ***** + + Function: void SetCombatAction(int chance, mixed val); + Examples: SetCombatAction(5, (: DoSomething :)); + SetCombatAction(5, ({ "!missile", "!fireball" })); + SetAction(5, ({ "The peasant looks angry." })); + + This function works exactly the same as SetAction(), except that these + actions only get triggered while the NPC is in combat. This is the + best place to have the NPC cast spells. + + ***** + + Function: varargs void SetCurrency(mixed val, int amount); + Examples: SetCurrency("gold", 100); + SetCurrency( ([ "gold" : 100, "electrum" : 1000 ]) ); + + This function allows you to set how much money an NPC is carrying. + The first syntax allows you to set one currency at a time. The second + allows you to set multiple currencies at once. Not that if you use + the second syntax, it will blow away any currencies the NPC might + already be carrying. + + ***** + + Function: mixed SetDie(mixed val); + Examples: SetDie("The black knight bleeds on you as he drops dead."); + SetDie((: CheckDie :)); + + If you pass a string, that string will be echoed as the NPC's death + message when it dies. If you pass a function, that function gets + called with the agent doing the killing, if any, as an argument. For + example, with the above example, the function that you write: + + int CheckDie(object killer); + + gets called. If you return 1, the NPC goes on to die. If you return + 0, the NPC does not die. In the event you prevent death, you need to + make some arrangements with the NPC's health points and such to make + sure it really is still alive. + + ***** + + Function: mixed SetEncounter(mixed val); + Examples: SetEncounter(40); + SetEncounter( (: CheckDwarf :) ); + SetEncounter( ({ str1, str2 }) ); + + This allows you to set up e behaviour for an NPC upon encountering + another living thing. Note that this behaviour occurrs for both + players and other NPC's. Using the first syntax, the NPC will simply + attack any other living thing with a charisma less than 40. The + second syntax calls the function you specify. You may have it do any + number of things, however, you must also return a 1 or a 0 from that + function. A 1 means that after the function is called, the NPC should + initiate combat against the thing it just encountered. A 0 means + carry on as usual. + + Finally, the third syntax is likely to be used in places other than + the create() funciton in the NPC. This syntax lets you set a list + names which are simply enemies to the NPC. More likely, you will be + using AddEncounter() and RemoveEncounter() for this. + + ***** + + Function: string *AddEncounter(string name); + Example: AddEncounter((string)this_player()->GetKeyName()); + + Adds a name to the list of names an NPC will attack on sight. + + ***** + + Function: string *RemoveEncounter(string name); + Example: RemoveEncounter((string)this_player()->GetKeyName()); + + Removes a name from the list of names an NPC will attack on sight. + + ***** + + Function: SetInventory(mapping inventory); + Examples: + SetInventory( ([ "/domains/Praxis/weapon/sword" : "wield sword" ]) ); + SetInventory( ([ "/domains/Praxix/etc/ruby" : 1 ]) ); + SetInventory( ([ "/domains/Praxis/etc/emerald" : -10 ]) ); + + This functions behaves almost identically to SetInventory() for rooms + (see /doc/build/Rooms). The big difference is that you may pass a + string in addition to a number as the value for any item you want in + the inventory. In the first example above, that string is the command + the NPC issues when the sword is cloned into its inventory. In other + words, if you want an NPC to do something special with an item it has + in its inventory, in this case wield the sword, you pass the command + string as the value instead of a number. + + Note that this means only one of such item will be cloned, and it + cannot be unique. + + ***** + II. Events + ***** + + The following events exist in NPC's. You should have a good grasp of + function overriding before overriding these functions. + + Event: varargs int eventDie(object target); + + This event is triggered any time the NPC is killed. The event returns + 1 if the NPC dies, 0 if it fails to die, and -1 on error. If you + intend to allow the NPC to die, you should call npc::eventDie(target) + and make sure it returns 1. + + ***** + + Event: int eventFollow(object dest, int chance); + + This event is triggered whenever an NPC is following another living + thing and that thing leaves the room. Returnung 1 means that the NPC + successfully followed the other being, and 0 means the NPC did not. + + ***** + 3. Manipulating limbs + ***** + + The basic set of limbs an NPC gets is generally set when you set its + race. You can get a list of supported NPC races through the mraces + command. Occassionally, however, you may want to create NPCs of + unique races, or with unique body structures. Or perhaps you want a + human whose right hand is already amputated. This section deals with + doing those things. + + Amputating a limb is simple. Call RemoveLimb("limb"). Note that that + is not useful for removing a limb that should not be there. Instead, + it is used for amputating a limb that looks amputated. + + If, on the other hand, you wish to remove a limb which simply should + not have been there in the first place, call DestLimb("limb"). + + The most simple case of actual limb manipulation, however, is to + change the basic structure of an individual NPC around for some + reason. For example, perhaps you wanted to add a tail to a human. + For this, you use the AddLimb() function. + + Function: varargs int AddLimb(string limb, string parent, int class, int *armours); + Examples: AddLimb("tail", "torso", 4) + AddLimb("head", "torso", 1, ({ A_HELMET, A_VISOR, A_AMULET })); + + This function adds a new limb to the NPC's body. The first argument + is the name of the limb to be added. The second argument is the name + of the limb to which it is attached. The third argument is the limb + class. Limb class is a number between 1 and 5. The lower the number, + the harder the limb is to remove. A limb class of 1 also means that + removal of the limb is fatal. The fourth, optional argument is a list + of armour types which may be worn on that limb. + + In some cases, you may wish to create a new race from scratch. This + requires adding every single limb manually. You first call SetRace() + with a special second argument to note that you are creating a new + race: + + SetRace("womble", 1); + + Then, you add the limbs for that race one by one. Make sure you call + SetRace() first. diff -c -r --new-file ds1.1/lib/doc/build/Properties ds2.1/lib/doc/build/Properties *** ds1.1/lib/doc/build/Properties Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Properties Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,93 ---- + Supported Properties + The Nightmare IV LPC Library + written by Descartes of Borg 950429 + + The Nightmare IV LPC Library allows creators to set dynamic variables in + objects which do not get saved when the object saves. The variables are + called properties. A property is an attribute of an object which is + considered fleeting. This document serves to list the properties + commonly used and their purpose. It is by no means complete, as the + point of having properties is to allow creators to build their own on the + fly. + + Note: All properties are 0 by default unless otherwise stated. + + Property: light + Values: integer between -6 and 6 + Light is a value generally between -6 and 6 which, for rooms, + determines how much light is naturally available in a room in daytime. + For other objects, it determines the degree to which the object is + able to modify the amount of light that exists in the room. If the + room is indoors, the light does not change based on the time of day. + + Property: no attack + Values: 1 to prevent attacks, 0 to allow them + Things cannot begin combat from inside a room with this property. + + Property: no bump + Values: 1 to prevent bumping, 0 to allow it + If a room, then nothing can be bumped from this room. If a living + thing, then it cannot be bumped. + + Property: no steal + Values: 1 to prevent stealing, 0 to allow it + This prevents stealing inside a room with this property. + + Property: no magic + Values: 1 to prevent magic, 0 to allow it + This prevents any magic from being used inside the room if set. + + Property: no paralyze + Values: 1 prevents paralysis from occurring in a room, 0 allows it + Stops any sort of thing which might cause paralysis from occurring in + a room. + + Property: no teleport + Values: 1 if teleporting is prohibited, 0 if allowed + Prevents people from teleporting to or from the room. + + Property: no clear + Values: 1 to prevent clearing, 0 to allow it + If set this prevents an avatar from clearing a wilderness room in + order to build a town. Not relevant to rooms in towns. + + Property: estates + Values: any non-negative number + Sets the number of estates which can be built in an area. No estates + may be built outside of towns. + + Property: magic item + Values: an array of strings describing the magic contained in an object + Allows you to mark specific objects as magic. For example, if a sword + has a magical lighting ability, you might do: + SetProperty("magic item", ({ "light" })); + + Property: lockpicking tool + Values: any integer marking how well lockpicking is enhanced + When picking a lock, the value of this property is calculated for each + object and added to the overall chance to pick the lock. + + Property: keep + Values: the name of whomever the object is kept for + While set, this object may only be picked up by the person whose name + matches the value of this property. If 0, anyone can pick it up + assuming it is normally gettable. + + Property: magic hold + Value: any integer + Is subtracted from the chance of success of anyone trying to pick a + lock. + + Property: enchantment + Value: any integer + Enchants any object to boost (or degrade) its performance of its + natural functions. + + Property: login + Value: a string representing a file name + Sets which room a player should login to at next login if they quit + from the room that has this property. For example, if you have a + treasure room that is protected, and therefore you do not want people + logging into it, you can call: + SetProperty("login", "/file/name/outside/this/room"); + to have the players login to the room outside. diff -c -r --new-file ds1.1/lib/doc/build/Quests ds2.1/lib/doc/build/Quests *** ds1.1/lib/doc/build/Quests Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Quests Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,35 ---- + Building Quests + from the Nightmare IV LPC Library + written by Descartes of Borg 950716 + + Unlike previous Nightmare versions, Nightmare IV has no support for + centralized quest administration. This was done under the belief that + coercive questing was among the least favourite features players have + mentioned about the MUDs I have encountered. Nevertheless, the + presence of quests is still an extrememly important part of any MUD. + Since the coercive nature (needing to complete quest X to raise to + level Y) has been removed, other ways to make questing worthwhile need + to be found. + + The first, and most obvious, is to properly reward the player with + money, items, and skill and stat points. The other bit of support is + for a title list. Each quest, or accomplishment, is added to a list + of accomplishments the player has. The player may display any of + those at any time as part of their title. + + The interface to this is simple: + + player_object->AddQuest(string title, string description); + + Example: + + this_player()->AddQuest("the slayer of frogs", + "You viciously slayed the evil frogs of Wernmeister that " + "threatened the peaceful town with warts and unabated fly murder."); + + In the player's biography, they will see the description along with + the date they accomplished the task. From their title list, they will + now be able to choose this title. + + Descartes of Borg + 950716 diff -c -r --new-file ds1.1/lib/doc/build/Rooms ds2.1/lib/doc/build/Rooms *** ds1.1/lib/doc/build/Rooms Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Rooms Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,487 ---- + Building Rooms + The Nightmare IV LPC Library + written by Descartes of Borg 950420 + + This document details how to build rooms using the Nightmare IV LPC + Library's inheritable room object. This document is divided into + simple room building and complex room building. The first part + teaches you about basic rooms. The second part tells you what + features are there to allow you to do creative things with the room object. + + ************************************************ + Part 1: Basic Room Building + ************************************************ + + I. The Simple Room + The simple room minimally looks like this: + + #include <lib.h> + + inherit LIB_ROOM; + + static void create() { + room::create(); + SetProperty("light", 2); + SetClimate("indoors"); + SetShort("an empty room"); + SetLong("An empty room with no exits leading anywhere. It is " + "completely barren with nothing to describe."); + } + + #include <lib.h> + This first line is one you need in any object. It defines the exact + location of objects which you inherit. In this case, the object is + LIB_ROOM. It is currently located at /lib/room.c. If we wanted to + change that location, however, we could do it easily since you only + reference LIB_ROOM. So lib.h is a file that says that LIB_ROOM is + "/lib/room". + + inherit LIB_ROOM; + The third line, the inherit line, says that this object will inherit + /lib/room.c. + + static void create() { + The fifth line begins the meat of any object you will write. This is + the beginning of a function. This one is called create(). If you are + curious, the static means no one can use the call command to call the + function. Do not worry about that too much, however, as it is always + something you put there for the create() function. + + The "void" part simply says that you are returning no value from the + function. See the LPC Basics textbook for more information on + functions. + + room::create(); + Inside the create() function are the calls which define what the + object will do. The first call calls the function create() in + /lib/room.c, the object you just inherited. /lib/room.c has its own + create() function which does some things needed in order to set up + your object. You need to make sure it gets called through this line. + + SetProperty("light", 2); + This sets the light in the room to be 2. In outdoors rooms, this is + the average light during day time. In indoor rooms, it is the average + light all the time. + + SetClimate("indoors") + Every room has a climate. An indoors room, among other things, is not + affected by weather or the time of day. + + SetShort("an empty room") + This is the description that the player sees when in brief mode. In + addition, in brief mode, obvious exit abbreviations are automatically + added. This is done through the SetObviousExits() function described + later. However, the short should be phrased in such a way that it + makes sense from something like a scry command which would say + something like: "You see Descartes in an empty room." + + SetLong("An empty room with no exits leading anywhere. It is " + "completely barren with nothing to describe."); + This sets the long description seen by the player when in verbose + mode. Note that items in the room as well as scents and sounds are + added to what the player sees automatically. + + That's it! You now have a room which no one can leave! + + II. Adding items + Approval on any decent MUD will eat you for lunch if you do not + describe your items. This is likely the most tedious part of area + building, however, it is also the part that largely makes the + difference between a dull area and a fun one. You must be sure to + make it so that anything a player might logically want to see in + detail in a room is described in detail. For example, say you have + the following long description for a room: + + You are in Monument Square, once known as Krasna Square. The two main + roads of Praxis intersect here, where all of Nightmare's people gather + in joy and sorrow. The road running north and south is called Centre + Path, while Boc La Road is the name of the road running east and west. + A magnificent monument rises above the square. + + You should have descriptions for the following items placed in your + room: + + square, monument, monument square, krasna square, roads, road, + intersection, people, centre path, boc la road, magnificent monument + + How to do this with a minimum of hassle: + + SetItems( ([ ({ "square", "monument square", "krasna square" }) : + "The central square of Praxis where citizens and adventurers " + "gather to chat and trade. Formerly known as Krasna Square, " + "is now known as Monument Square as thanks to those who helped " + "to build the town", + ({ "monument", "magnificent monument" }) : "A giant monolith " + "rising above Monument Square", + ({ "intersection", "road", "roads" }) : "The two main roads of Praxis " + "intersect in Monument Square. The one to the north and south " + "is called Centre Path, while the other is Boc La Road.", + ({ "people", "adventurers", "citizens" }) : "A varied group of " + "people from countless realms hanging about talking and trading.", + "centre path" : "The main road leading north to the North Forest " + "from Praxis, and south to the sea.", + "boc la road" : "The main east-west road through Praxis, going " + "east towards the jungle, and west towards the Daroq Mountains." ]) ); + + That may seem like a mouthful, but it is easier to break down into + smaller points and see what is going on. The SetItems() prototype + looks like this: + + mapping SetItems(mapping items); + + That means it accepts a data type called a mapping as the argument and + returns a new mapping of items. A mapping is a special data type in + LPC that allows you to associate two values together, for example, to + associate an item with its description. For example, above we wanted + to associate the items "monument" and "magnificent monument" with the + description "A giant monolith rising above Monument Square". To do + that, a mapping looks like this: + + ([ value1 : assoc_value1 ]) + + where assoc_value1 is the value associated with value1. In this case, + we might have something like: + + ([ "monument" : "A giant monolith rising above Monument Square." ]) + + But, we also wanted to associate "magnificent monument" with this + description. One way, which is perfectly legitimate, would be: + + ([ "monument" : "A giant monolith rising above Monument Square", + "magnificent monument" : "A giant monolith rising above Monument Square" ]) + + But that would be damned annoying, especially with long descriptions + or things with a lot of synonyms. You can therefore group values + which have the same description together using array notation: + ({ value1, value2, value3 }) + + And thus, make that mapping look like: + + ([ ({ "monument", "magnificent monument" }) : "A giant monolith rising " + "above Monument Square." ]) + + To complete setting the items, you simply add other item/description + pairs separated by commas: + + ([ ({ "monument", "monument square" }) : "A giant monolith rising " + "above Monument Square.", + "house" : "A little white house with white picket fences." ]) + + Mappings are a rather difficult concept to grasp, but once grasped + they are very powerful. You should take a look at some sample code + from /domains/Examples/room to get a good idea of what proper code + looks like. In addition, there is a chapter in Intermediate LPC + dedicated to the concept. Finally, you can always mail + borg@imaginary.com to ask questions. + + III. Adding Exits and Enters + If you understand the section above, exits and enters are simple. + They too use mappings, but less complicated ones: + + SetExits( ([ "north" : "/domains/Praxis/n_centre1", + "south" : "/domains/Praxis/s_centre1", + "east" : "/domains/Praxis/e_boc_la1", + "west" : "/domains/Praxis/w_boc_la1" ]) ); + + SetEnters( ([ "hall" : "/domains/Praxis/town_hall", + "pub" : "/domains/Praxis/pub" ]) ); + + With an exit mapping, you simply match the direction to the room to + which it leads. With an enter mapping, you match a thing being + entered with the room to which it leads. + + Unlike other LPC Libraries, the Nightmare IV LPC Library distinguishes + between the concept of motion towards and motion into. Motion towards + is exemplified by the "go" command, which is affected by SetExits(). + For example, to go east, you type "go east". You are simply going + towards the east (Note that "go east" is by default aliased to "e"). + + Motion into is exemplified by the "enter" command, which is affected + by SetEnters(). Enter marks anything you enter into, for example a + building or bushes or the like. In the above example, a player would + issue the command "enter pub" to enter the pub. + + IV. Adding Objects + If you want to add physical objects into your room, you use the + SetInventory() function. For example, if you wanted to place a balrog + in the room: + + SetInventory(([ "/domains/Praxis/npc/balrog" : 1 ]); + + Every reset, the room will then check to see if any balrogs are in the + room. If no balrogs are in the room it will clone 1. Again, this is + another function using a mapping. In this case it is associating the + file name of an object with how many of that object should be in the + room at every reset. If you wanted 5 balrogs in the room, you would + have changed the 1 to 5. + + V. Adding Smells, Listens, and Searches + + The functions: + SetSmell() + SetSearch() + SetListen() + + All work identically to the SetItems() function. That is they match + things you can smell, listen, search to descriptions which the player + sees when they smell, listen, search the item. + + For example: + + SetSmell( ([ "monument" : "It smells of obsidian.", + "road" : "It smells dusty.", + ({ "pub", "bar" }) : "It smells of alcohol." ]) ); + + If a player types: + "smell monument" + then they see + "It smells of obsidian." + + One unique thing about these three functions, however, is that you can + use the special thing "default" to set a smell, listen, or search that + occurs when no object is specified. For example, + + SetSmell(([ "default" : "It really stinks here." ]) ); + + Will have the player see "It really stinks here." when they simply + type "smell". In addition, this is the smell the player sees when + they simply walk into a room. + + VI. Miscellaneous stuff + + SetObviousExits("n, s, e") + Sets an obvious exits string which gets seen in brief mode and by + newbies in verbose mode. Generally, this should consist of the + abbreviations for the room's obvious exits only. + + SetTown("Praxis") + For rooms which are considered part of a town, you must specify that + they are part of the town through this function. In this example, the + room is set to be in the town of Praxis. See the document + /doc/build/Towns for more information on towns. + + SetDayLong("The sky lights up the endless fields of wheat which stand " + "before you."); + SetNightLong("You are standing in a pitch black field of wheat."); + Instead of using SetLong(), you can call both of these functions to + give different long descriptions for day and night. + + SetGravity(2.0) + This makes things in the room twice as heavy as normal. + + SetDoor("east", "/domains/Praxis/doors/red_door"); + Sets a door to the east which is the file + "/domains/Praxis/doors/red_door.c". You should have an exit to the + east, and you should do this AFTER you have called SetItems(). See + the document /doc/build/Doors for detailed information on door + building. + + VII. Summary + + Here is a room that uses everything described above: + + #include <lib.h> + + inherit LIB_ROOM; + + static void create() { + room::create(); + SetProperty("light", 2); + SetClimate("temperate"); + SetTown("Praxis"); + SetShort("a peaceful park"); + SetDayLong("The light of the sun shines down upon an open field " + "in the middle of Praxis known as Kronos Park. In spite " + "of the time of day, no one is around. East Boc La " + "Road is to the south."); + SetNightLong("Kronos Park is a poorly lit haven for rogues in the " + "cover of night. It is safest to head back south " + "towards the lights of East Boc La Road"); + SetItems( ([ ({ "field", "park" }) : "A wide open park in the " + "center of Praxis." ]) ); + SetSearch( ([ "field" : "You get dirt all over your hands." ]) ); + SetSmell( ([ "default" : "You smell grass after a fresh rain.", + "dirt" : "It smells like... dirt!" ]) ); + SetExits( ([ "south" : "/domains/Praxis/e_boc_la3" ]) ); + SetInventory( ([ "/domains/Praxis/npc/rogue" : 2 ]) ); + } + + ************************************************ + Part 2: Advanced Room Building + ************************************************ + I. Functionals + MudOS has a data type called a functional. Most room functions take a + functional as an argument instead of a string. What this does is + allow you to specify a function to get called in order to determine + the value rather than set it as a string which cannot be changed. For + example, if you wanted to set a long description that varied depending the + status of a door: + + #include <lib.h> + + inherit LIB_ROOM; + + string CheckDoor(string useless); + + static void create() { + room::create(); + SetProperty("light", 2); + SetClimate("indoors"); + SetShort("an indoor room with a door"); + SetLong( (: CheckDoor :) ); + SetExits( ([ "east" : "/domains/Praxis/east_room" ]) ); + SetDoor("east", "/domains/Praxis/doors/red_door"); + } + + string CheckDoor(string useless) { + string tmp; + + tmp = "You are in a plain indoor room with a door. "; + if( (int)"/domains/Praxis/doors/red_door"->GetOpen() ) + tmp += "The door is open."; + else tmp += "The door is closed."; + return tmp; + } + + In this example, a function called CheckDoor() was written to + determine exactly what the long description should be. This is done + because in create(), you have no idea what the status of the door will + be from moment to moment. Using a function, you can therefore + determine what the long description is at the time it is needed. + + Functionals can reference any function anywhere on the MUD, including + efuns. See /doc/lpc/data_types/functionals for details on them. For + the sake of this document however, you note a functional using smileys + :). + + (: CheckDoor :) means the function CheckDoor() in this object. You + can also specify function in other objects, for example: + (: call_other, this_player(), "GetName" :) would refer to GetName() in + the person who was this_player() AT THE TIME THE FUNCTIONAL WAS + CREATED. + + Notice at the top of the file that CheckDoor() was prototyped. You + must prototype any function you reference inside your objects. The + expression (: CheckDoor :) constitutes as a reference, and thus makes + you need to prototype the function. + + The rest of this portion describes individual function calls using + functionals. The functional prototype part is how your functional + should be declared.: + + SetShort(string | function) + Functional prototype: string ShortFunc(); + Example: SetShort( (: MyShort :) ); + If you pass it a function, then this function gets called to determine + the short description. The function should return a string which will + be used as the short description. + + SetLong(string | function) + Functional prototype: string LongFunc(string unused) + Example: SetLong( (: MyLong :) ); + This function should return a string which will be used as the long + description for the room. The argument "unused" is just that, unused + in this context. It is something used for other objects. + + SetItems(mapping mp); + Functional prototype: string ItemFunc(string item); + Example: SetItems( ([ "house" : (: LookHouse :) ]) ); + This function should return a string to be used for the item + description. The argument is passed the name of the item being looked + at, so you can use the same function for multiple items. + + SetSearch(mapping mp) + Alternate: SetSearch(string item, string | function desc) + Functional prototype: string SearchFunc(string item); + Examples: SetSearch( ([ "grass" : (: SearchGrass :) ]) ); + SetSearch("grass", (: SearchGrass :)); + Note that there are two forms to SetSearch(), useful depending on how + many searches you are setting at once. If you have a search function, + then that function should return a string which is what they will see. + The argument passed is the item being searched. + + SetSmell() + SetListem() + see SetSearch() + + II. Advanced Exits + SetExits() is fairly straight forward. However, there exists another + function for exits called AddExit(). It allows you to add one exit at + a time (useful if say a player searches and finds a new exit) as well + as give functional power to exits. The prototype for AddExit() is: + + varargs mapping AddExit(string dir, string dest, function pre, function post); + + The varargs part of the prototype simply means you can call it using + less than the full number of arguments specified. In this case, the + minimum call is: + + AddExit("east", "/domains/Praxis/square"); + + The last two arguments are called pre-exit functions and post exit + functions. The pre-exit function gets called when a player issues a + command to leave the room, but before the player is allowed to leave. + Depending on the return value of the function, the player is allowed + or denied the right to leave. For example: + + AddExit("north", "/domains/Praxis/square", (: PreExit :)); + + int PreExit(string dir) { + if( !avatarp(this_player()) ) { + write("You are too lowly to go that way!"); + return 0; + } + else return 1; + } + + In other words, if the player is an avatar, they can go north. + Otherwise they cannot. The prototype is: + + int PreExit(string dir); + + where the return value is 1 or 0 for can or cannot leave, and the + argument dir is the direction in which the player is exiting. + + Post exit functions work a little differently since it makes no sense + to prevent someone from leaving once they have left. The prototype + looks like: + + void PostExit(string dir); + + This simply allows you to do processing once the player is gone. If + you wish a post exit without a pre exit, then: + + AddExit("north", "/domains/Praxis/square"", 0, (: PostExit :)); + + Enters work exactly the same way. + + Please read about the events CanReceive() and CanRelease(), as those + may be more appropriate places to do what you want. Remember, this + only prevents a player from using the "go" command to go in that + direction. CanReceive() in the other room would be better if your + desire is to keep non-avatars out of the square at any cost. + + III. Other Functions + + AddExit() + RemoveExit() + AddEnter() + RemoveEnter() + RemoveSearch() + RemoveSmell() + RemoveListen() + AddItem() + RemoveItem() + + All of the above Remove*() functions take a single string argument + specifying what it is that is being removed. For example: + + RemoveExit("east") + + removes the exit to the east. + + AddItem(string item, mixed val) + Adds a single item. Val can be a string or function. + + Descartes of Borg + borg@imaginary.com diff -c -r --new-file ds1.1/lib/doc/build/Sentients ds2.1/lib/doc/build/Sentients *** ds1.1/lib/doc/build/Sentients Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Sentients Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,235 ---- + Building Sentient Non-Player Characters + The Nightmare IV Object Library + written by Descartes of Borg 951127 + + One thing most everyone wants to see are monsters that react more + intelligently to user input. The fact is, however, that most monsters + in the game only need a small, basic behaviour set. Nevertheless, in + order to make an area interesting, there should be some monsters which + stand out as unique and purposeful. The problem about building such + monsters is that they use a lot of processing time. + + In order to make sure most monsters which do not need such + intelligence do not waste processing time on such activities, the + Nightmare Object Library separates non-player characters into two + classes: dumb monsters, which are basic mindless automata and + sentients, monsters which react more intelligently to their + environment. + + This document describes sentients. Before looking at this document, + it is highly recommended that you be familiar with the document + /doc/build/NPC which details non-player characters. Sentients are + non-player characters, so everthing which applies to non-player + characters also applies to sentients. + + ***** + + Currently, a few basic behaviours distinguish sentients from normal + npcs. Those behaviours are the ability to intelligently move about + the mud and to react to user speech. Nightmare thus provides the + following functions to allow you to easily have an sentient enact + those behaviours: + + mapping SetTalkResponses(mapping mp); + mixed AddTalkResponse(string str, mixed val); + int RemoveTalkResponse(string str); + + mapping SetCommandResponses(mapping mp); + mixed AddCommandResponse(string str, mixed val); + int RemoveCommandResponse(string str); + + varargs int SetWander(int speed, string *path, int recurse); + string *SetWanderPath(string *path); + + int SetWanderRecurse(int x); + + int SetWanderSpeed(int x); + + ***** + + Making NPCs react to user speech + + You may want to have NPCs react to things players say. To that end, + the following functions exist: + + mapping SetTalkResponses(mapping mp); + mixed AddTalkResponse(string str, mixed val); + int RemoveTalkResponse(string str); + + Function: mapping SetTalkResponses(mapping mp) + Example: SetTalkResponses( ([ "square" : "The square is east of here.", + "house" : "Isn't that an ugly house?" ]) ); + + This function allows you to set a list of responses to given phrases. + For example, if you put this code in a sentient and a player said + "Where is the square?" or "Your frog is certainly square.", your NPC + would have said "The square is east of here.". Note therefore that + the NPC is only looking for the keys you place in there. You could + have restricted it to "where is the square" instead of "square", but + then someone asking "Where's the square" would be missed. + + Also note that phrases should be in lower case. It will match to + upper case words automatically. + + Finally, you can either give a string or a function as the match to a + phrase. If the match is a string, the NPC simply says the string in + the NPC's native tongue. If, however, the match is a function, that + function will get called. + + ***** + + Function: mixed AddTalkResponse(string str, mixed val); + Example: AddTalkResponse("in the house", (: HouseFunc :)); + + Matches an individual phrase to a string or function. As with + SetTalkResponses(), if the match is a string, the NPC simply says the + string in response to the phrase. If it is a function, that function + gets called. + + ***** + + Function: int RemoveTalkResponse(string str); + Example: RemoveTalkResponse("house"); + + Removes the previous set or added talk response from the NPC. + + ***** + + Making NPCs react to user directives + + Nightmare supports a special command, the "ask" command. A player may + use the ask command to ask an NPC to perform a certain task. For + example, "ask the healer to mend my right leg". There is a special + event in NPC's which responds to this called eventAsk(). In order to + make responding to this easier, however, Nightmare has the + CommandResponse functions. The command response functions allow NPC's + to respond based on commands, like "mend". + + ***** + + Function: mapping SetCommandResponses(mapping mp); + Example: SetCommandResponses( ([ "heal", "I cannot heal people" ]) ); + + Allows you to match commands to either strings or functions. Matched + functions get called with the command as the first argument, and + command arguments as the second argument. For example, if you had: + SetCommandResponses("give", (: give :)); + Your give() function would get called with "give" as the first + argument and "me the sword" as the second argument in response to a + player issuing the command "ask the monster to give me the sword". + + ***** + + Function: mixed AddCommandResponse(string str, mixed val); + Example: AddCommandResponse("give", (: give :)); + + This allows you to add to the list of commands to which the NPC + responds. The NPC responds to those commands as outlined for + SetCommandResponses(). + + ***** + + Function: int RemoveCommandResponse(string str); + Example: RemoveCommandResponse("give") + + Removes a previously set command response. + + ***** + + Making NPCs move about the game intelligently + + A sticky subject on most muds is that of wandering monsters. When + done poorly, they can waste resources to a great degree. Nightmare, + however, works to avoid wasting resources while getting the most out + of allowing monsters to move about. + + Nightmare supports two types of wandering monsters: those which have + pre-determined paths and others which are true wanderers. True + wanderers, those who simply randomly choose paths are subject to the + following restrictions: + They may not move into rooms not yet loaded in memory. + They will not try to open closed doors. + The first restriction is the most important to note. This means that + the NPC will not wander into rooms that have not been recently visited + by some player. This avoids the problem NPCs cause on many muds of + uselessly loading rooms that only the monster will ever see. + + Monsters given specific paths to wander are not subject to the above + restrictions. Of course, they cannot wander through closed doors. + But you can make part of their path to open a closed door. In + addition, since such monsters have very specific sets of rooms into + which they can travel, they are not in danger of needlessly loading a + zillion rooms. + + ***** + + Function: varargs int SetWander(int speed, string *path, int recurse); + Examples: + SetWander(5); + SetWander(5, ({ "go north", "open door", "enter hut", "go west" })); + SetWander(5, ({ "go north", "open door", "enter hut", "go west", + "go south" }), 1); + + This is the function you will almost always use in create() to make a + sentient wander. Only one of the three possible arguments is + mandatory, that being the speed. The speed is simply the number of + heart beats between attempts to move. Thus, the higher the number, + the slower the movement of the monster. + + The second argument, if given, is a list of commands which will be + executed in order by the monster. If it is not given, the monster + will be assumed to be a true wanderer. In other words, the first time + the monster tries to wander, the monster will "go north". The second + time, he will "open door". The third, he will "enter hut", etc. + + The third argument is either 1 or 0. If 1, that means once the + monster has completed the path, it will use the first command in the + list the next time it tries to wander. If 0, it will cease to issue + commands once it has cycled through the list. + + You might note that between the time the above monster opens the door + and enters the hut, somebody could come along and shut the door. How + can you deal with that? You could do: + SetWander(5, ({ "go north", ({ "open door", "enter hut" }) })); + You will notice here that the second member of the command array is + itself an array instead of a string. In that case, all members of + that array get executed as part of that wander. In this case it helps + make sure no one closes the door between when the monster tries to + open it and when it tries to pass through the door. + + For even more flexibility, you can make elements of the array into + functions. Instead of executing a command in a wander turn, the + function you provide instead gets called. For example: + SetWander(5, ({ "go north", (: kill_anyone :), "go south" }), 1); + Where the function kill_anyone() has the monster kill any players in + that room. Thus, this monster sits in its room and occasionally pops + its head one room to the north to kill anyone sitting there. + + ***** + + Function: string *SetWanderPath(string *path); + Example: SetWanderPath(({ "go north", "go south" })) + + Allows you to set the monster's wander path independent of other + settings. The wander path will never get executed, however, unless + the monster's wander speed is greater than 0. + + ***** + + Function: int SetWanderRecurse(int x); + Example: SetWanderRecurse(1); + + Allows you to make the monster's wander path recurse independent of + other settings. This is meaningless, however, unless the monster's + wander speed is greater than 0 and a wander path is set for it. + + ***** + + Function: int SetWanderSpeed(int x); + Example: SetWanderSpeed(5); + + Allows you to set the monster's wander speed independent of other + settings. This is NOT the same as SetWander(5). SetWander() will + clear out any previous wander path and wander recurse settings. This + function has no effect on the monster's wander path or wander recurse. + diff -c -r --new-file ds1.1/lib/doc/build/Towns ds2.1/lib/doc/build/Towns *** ds1.1/lib/doc/build/Towns Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Towns Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,90 ---- + Building Towns + The Nightmare IV LPC Library + written by Descartes of Borg 950429 + + The Nightmare IV LPC Library contains support for towns, which is in + fact very minimal from the mudlib level. If, however, you wish to + structure your MUD to be centered around the concept as Nightmare LPMud + is, then you need to understand how to build a town. This document + describes the building of towns using the Nightmare IV LPC Library. + + I. What Is a Town? + A town is simply a collection of rooms which have the same value set + for Town. If done poorly, this is all it is. If done right, however, + a town becomes the center of the games' social structure. If you + decide to build a town in your area, the first thing you need to do is + isolate it. All towns should be surrounded by vast, vast areas of + wilderness of some sort. This may mean desert, forest, jungle, or + whatever. You may or may not want to have a road which links it to + the rest of civilization. + + Rooms are considered "wilderness" by default. That is, if you never + set the town in them, they are considered wilderness. To make a room + part of a town, you need to call SetTown() from create() of the room: + + SetTown("Praxis"); + + Capitalize your town name properly. + + Next you need to decide how many estates may be built in the room. + Ideally, towns are expanding and changing things. Upper level players + have the ability to build estates in their home towns. Of course, ten + estates in one room is crowded. Generally you should limit the number + of estates to what would logically fit in a given room. For example, + if you are on a road at the edge of town with nothing about, then + allowing two estates makes sense. On the other hand, in the middle of + an intersection of two roads, there is hardly any room for an estate + to be built. To allow estates to be built in a room: + + SetProperty("estates", 2); + + This allows two estates to be built off of this room. + + As stated above, towns are expanding. This is why they should be + situated far apart. Too close together it is hard for them to expand + without changing the overall map of the game. Therefore, when your + town has gotten as full as can be handled, then you simply move to + outlying rooms and make them part of the town by setting their town. + In addition, give them the capacity for estates. Do not forget to + change room descriptions and allow for needed roads! + + II. What do I put in towns? + The first section described what is minimally needed for a town from a + code point of view. This section describes what sorts of things you + should put in your towns. Most are optional, however, you do need to + add something called an adventurer's hall. An adventurer's hall is + the default start room for the town for anyone who chooses the town as + their home town. In order to make it their home town, they go to the + adventurer's hall and pay a fee (generally determined by approval) to + move to this town. Until that person builds an estate in the town, + the adventurer's hall is their default starting point. + + Beyond that, the only other thing required is a real estate office for + selling estates. This is an inheritable from /lib/sales.c + (LIB_SALES). Approval determines what your local land value is, and + you fill in the descriptions. For information on advanced coding of + sales offices, see the document /doc/build/Sales. + + Nothing else is required. Of course, your land value (the amount + people pay to live and build in your town) is determined by the sorts + of services your town offers. No town should offer all services. And + certainly, the services your town offers should reflect the nature of + the region in which you are building. Are you an isolated, small + town? Then few services will be available. Are you a central, large + town? Then a majority of services should be available. + + Services include: + shops of different types + bars and pubs + restaurants + libraries for learning languages + class halls + town council rooms + + This list will probably expand over time, but it provides a good + starting point for common services. + + Descartes of Borg + borg@imaginary.com + + diff -c -r --new-file ds1.1/lib/doc/build/Vendors ds2.1/lib/doc/build/Vendors *** ds1.1/lib/doc/build/Vendors Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Vendors Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,63 ---- + Building Store Vendors + The Nightmare IV LPC Library + written by Descartes of Borg 950528 + + This document details the creation of vendor objects, NPC's which buy + and sell items. Note that vendors are NPC's, so everything in the + document on building NPC's applies to vendors. It is recommended that + you be completely familiar with that document before moving on to this + one. + + Building vendors is actually quite simple, with very little required + beyond the NPC requirements. In fact, only the following function + calls are unique to vendors: + + string SetLocalCurrency(string currency); + string SetStorageRoom(string room); + int SetMaxItems(int num); + int SetVendorType(int vt); + + One special note, however, is that the skill "bargaining" is extremely + important to vendors. Namely, the higher the bargaining, the harder + it is for players to get decent prices. + + ***** + string SetLocalCurrency(string curr); + ***** + + Example: SetLocalCurrency("electrum"); + + Sets the currency which the vendor will use for doing business. The + currencies should be approved by the approval team. + + ***** + string SetStorageRoom(string room); + ***** + + Example: SetStorageRoom("/domains/Praxis/horace_storage"); + + Identifies the file name of the room in which the vendor will be + storing items for sale. This room should never be accessible to + players. + + ***** + int SetMaxItems(int num); + ***** + + Example: SetMaxItems(60); + + Sets the maximum number of items a vendor can keep in storage at any + given time. Refer to approval documentation for proper numbers for + this. + + ***** + int SetVendorType(int type); + ***** + + Examples: + SetVendorType(VT_WEAPON); + SetVendorType(VT_ARMOUR | VT_WEAPON); + + Sets which types of items a vendor will buy and sell. A list of all + vendor types is in /include/vendor_types.h. You may allow a vendor to + sell multiple types using the | operator. diff -c -r --new-file ds1.1/lib/doc/build/Weapons ds2.1/lib/doc/build/Weapons *** ds1.1/lib/doc/build/Weapons Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/build/Weapons Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,212 ---- + Building Weapons + The Nightmare IV LPC Library + written by Descartes of Borg 950429 + + All items in the Nightmare LPC Library (descendants of /lib/item.c) + are weapons. A player can, for example, use a can of spam as a + weapon. However, they are set up as extremely pathetic weapons. This + document describes in detail how to make an object into a real weapon. + + I. Basic Stuff + The basic weapon is exactly the same as the basic item. You can do + anything to it that can be done to other items. For details on items, + see /doc/build/Items. The simple weapon should look like this: + + #include <lib.h> + #include <damage_types.h> + #include <vendor_types.h> + + inherit LIB_ITEM; + + static void create() { + item::create(); + SetKeyName("short sword"); + SetId( ({ "sword", "short sword", "a short sword" }) ); + SetAdjectives( ({ "short" }) ); + SetShort("a short sword"); + SetLong("A rusty short sword with specs of blood on it."); + SetVendorType(VT_WEAPON); + SetDamagePoints(1500); + SetClass(12); + SetValue(150); + SetMass(100); + SetWeaponType("blade"); + SetDamageType(BLADE); + } + + The last part is what differs from regular items. Note the functions: + + SetVendorType() + SetClass() + SetWeaponType() + SetDamageType() + + The available vendor types can be found by reading the file + /include/vendor_types.h. Similarly, damage types may be found by + reading /include/damage_types.h. The vendor type states what sort of + stores can carry this item. VT_WEAPON should almost ALWAYS be the + vendor type you give for weapons. + + SetClass() + The class is the basic weapon strength. It is how much damage gets + done without any modification. This number ranges between 1 and 100, + where 1 is a pathetic weapon (the class for basic items) and 100 is + probably bordering on illegal. + + SetWeaponType() + This sets what sort of attack skill the player needs to use this + weapon. The weapon types are: + blade + knife + blunt + projectile + + SetDamageType() + Damage types, again, are found in /include/damage_types.h. This sets + what type of damage is done by this weapon to its victims. + + II. Wield Functions + + mixed SetWield(string | function) + Examples: + SetWield("The short sword feels dull as you wield it."); + SetWield( (: WieldMe :) ); + + If you pass a string to SetWield(), then the player sees that string + whenever they wield the weapon. If, on the other hand, you pass a + function, then that function will get called just before the weapon is + wielded when the player issues the wield command. The function you + pass should be written in the form of: + + int WieldMe(); + + If the function returns 1, then the player can wield the weapon. If + it returns 0, then the player cannot wield the weapon. Note that if + you have a wield function, you are responsible for all messaging to + the player to let the player know that they can/cannot wield the + weapon. Example: + + int WieldMe() { + if( (int)this_player()->ClassMember("fighter") ) { + write("The short sword gives you power as you wield it."); + say((string)this_player()->GetName() + " wields a short sword."); + return 1; + } + else { + write("You are not worthy of this short sword."); + return 0; + } + } + + + III. Modifying Stats and Skills + A common thing people like to do with weapons is temporarily modify a + player's skills. This is done by making use of the function + AddStatBonus() and AddSkillBonus(). Most of the time this is done + through a SetWield() function. + + void AddStatBonus(string stat, function f); + void AddSkillBonus(string stat, function f); + + Examples: + this_player()->AddStatBonus("wisdom", (: CheckStat :)); + this_player()->AddSkillBonus("blade attack", (: CheckSkill :)); + + The functions then have the format: + + int CheckWhatever(string stat_or_skill); + + NOTE: You should always check whether the bonus is still in effect. + For example, make sure the weapon is still wielded if it results from + wielding the weapon. For example: + + #include <lib.h> + + inherit LIB_ITEM; + + int DoWield() + int CheckBlade(string skill); + + static void create() { + ... + SetWield((: DoWield :)); + ... + } + + int DoWield() { + this_player()->AddSkillBonus("blade attack", (: CheckBlade :) ); + write("You wield the short sword."); + say((string)this_player()->GetName() + " wields a short sword."); + return 1; + } + + int CheckBlade(string skill) { + if( !GetWorn() ) { + previous_object()->RemoveSkillBonus("blade", this_object()); + return 0; + } + else return 5; + } + + + In other words, this weapon will give its wielder a blade attack bonus + of 5. Note that you must use previous_object() in CheckBlade() and + NOT this_player() because there is no way of knowing who this_player() + is at the time. You do know, however, that the object calling + CheckBlade() is always the player for whom the skill bonus is made. + Always remember to remove bonuses. + + IV. Modifying Hits + The Nightmare IV LPC Library uses an event driven combat system. With + respect to weapons, a round of combat is broken down into the + following events: + + 1. The person wielding the weapon uses it. + 2. If they cannot hit a motionless target, the round ends. + 3. If the target dodges the attack, the round ends. + 4. eventStrike() is called in the weapon to determine how much damage + the weapon can do. + 5. eventReceiveDamage() is called in the target object. This in turn: + a. Calls eventReceiveDamage() in all armour objects, which each: + i. Calls eventReceiveDamage() in the weapon + ii. The weapon wears down a bit + b. The armour wears down a bit + c. The amount of armour damage absorbed is returned + d. The target objects loses health points. + f. The amount of damage done is returned. + 6. Skill and stat points are added. + + Note the two important functions which get called in weapon.c: + + int eventStrike(object ob); + int eventReceiveDamage(int type, int amount, int unused, mixed limbs); + + By default, eventStrike() returns the value of GetClass(). However, + you can modify this value by overriding the eventStrike(). For + example: + + int eventStrike(object target) { + if( (string)target->GetRace() != "orc" ) return item::eventStrike(target); + message("environment", "The orc slayer makes a nasty sound!", + environment(target)); + return item::eventStrike(target) + random(10); + } + + NOTE: You should always use item::eventStrike() rather than hard coded + values since weapon class deteriorates over time. + + In this example, a random(10) points of extra damage gets done to + orcs. This would be the orc slayer weapon of ancient fame. + + For those familiar with hit functions in the old Nightmare Mudlibs, + this would be roughly equivalent to that. + + Another place where you can make things happen is in + eventDeteriorate() which gets called by eventReceieveDamage(). This is + where a weapon wears down from the shock which armour has absorbed + from it. For weapons, there is not much which can be done here, but + this document points it out for the creative who feel they might be able to do + somthing with it. + + Descartes of Borg + borg@imaginary.com diff -c -r --new-file ds1.1/lib/doc/efun/all/TODO ds2.1/lib/doc/efun/all/TODO *** ds1.1/lib/doc/efun/all/TODO Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/TODO Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + query_ip_port(void|object) [PACKAGE_CONTRIB] + mixed query_notify_fail() [!NO_ADD_ACTION] [PACKAGE_CONTRIB] + int remove_interactive(object) [PACKAGE_CONTRIB] + int remove_shadow(object ob) [!NO_SHADOWS] [PACKAGE_CONTRIB] + int replaceable(object, void | string array) [PACKAGE_CONTRIB] + float array rotate_x(float array, float) [PACKAGE_MATRIX] + float array rotate_y(float array, float) [PACKAGE_MATRIX] + float array rotate_z(float array, float) [PACKAGE_MATRIX] + float array scale(float array, float) [PACKAGE_MATRIX] + void set_this_player(object | int) [NO_ADD_ACTION] + void store_variable(string, mixed) [PACKAGE_CONTRIB] + string terminal_colour(string, mapping) [PACKAGE_CONTRIB] + float array translate(float array, float, float, float) [PACKAGE_MATRIX] + mapping unique_mapping(array, string|function, ...) + string upper_case(string) [PACKAGE_CONTRIB] + string array variables(object, int default: 0); [PACKAGE_CONTRIB] diff -c -r --new-file ds1.1/lib/doc/efun/all/acos ds2.1/lib/doc/efun/all/acos *** ds1.1/lib/doc/efun/all/acos Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/acos Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + acos - return the arccosine of a float + + float acos( float f ); + + This efun is available only if PACKAGE_MATH is compiled in to the driver. + + Returns the arccosine of its argument, `f', measured in radians. + + See also: + asin, + atan, + cos, + sin, + tan diff -c -r --new-file ds1.1/lib/doc/efun/all/add_action ds2.1/lib/doc/efun/all/add_action *** ds1.1/lib/doc/efun/all/add_action Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/add_action Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,49 ---- + add_action - bind a command verb to a local function + + void add_action( string | function fun, string | string array cmd ); + + void add_action( string | function fun, string | string array cmd, int flag ); + + This efun is only available if NO_ADD_ACTION isn't defined. + + Set up a function 'fun' to be called the a user types the command 'cmd'. + (What is the command is determined by the first 'word' which consists + of all the characters before the first space, with the exception of + verbs that don't need a space; see below). + + If 'cmd' is an array, then that function will be called for any of the + commands in the array. 'fun' can either be a string which is the name + of a function in the object adding the command, or a function pointer. + + Functions called by a user command will get the rest of the command line + as a string. It must then return 0 if it was the wrong command, otherwise 1. + If 1 is returned, no further parsing is done; if 0 is returned, other + commands will be checked (possibly the same command added by a different + object). If no command is found, the default error message will be sent + to the player (traditionally, 'What?' but see also notify_fail()) + + For functions which can be called by more than one command, check query_verb() + to see which command was used. + + Note: add_action() does not add commands globally; it only adds commands to + this_user(), and the object must be 'close' to the user it is adding commands + to. + + Usually add_action() is called only from an init() routine. The object that + defines commands must be 'close' to the user, either being the user, + being carried by the user, being the room around the user, or being an + object in the same room as the user. + + Since init() is called when a user moves 'close' to an object, it is a + convenient time to add such commands. The commands are removed when the + user moves out of range (or the object does). + + If argument 'flag' is 1, then only the leading characters of the command has + to match the verb 'cmd' and the entire verb is returned by query_verb(). If + argument 'flag' is 2, then again, only the leading characters must match, + but query_verb() will only return the characters following 'cmd'. + + See also: + query_verb, + remove_action, + init diff -c -r --new-file ds1.1/lib/doc/efun/all/all_inventory ds2.1/lib/doc/efun/all/all_inventory *** ds1.1/lib/doc/efun/all/all_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/all_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + all_inventory - return the inventory of an object + + object array all_inventory( object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled into the driver. + + Returns an array of the objects contained inside of 'ob'. If 'ob' is + omitted, this_object() is used. + + See also: + deep_inventory, + environment + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/all_previous_objects ds2.1/lib/doc/efun/all/all_previous_objects *** ds1.1/lib/doc/efun/all/all_previous_objects Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/all_previous_objects Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + all_previous_objects - returns an array of objects that called the current function + + object array all_previous_objects(); + + Returns an array of objects that called current function. + Note that local function calls do not set previous_object() to the current + object, but leave it unchanged. + + The first element of the array is previous_object(), followed by + previous_object(1), etc ... + + See also: + call_other, + origin, + previous_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/allocate ds2.1/lib/doc/efun/all/allocate *** ds1.1/lib/doc/efun/all/allocate Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/allocate Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + allocate - allocate an array + + array allocate( int size ); + + Allocate an array of <size> elements. The number of elements must be >= 0 + and not bigger than a system maximum (usually ~10000). All elements are + initialized to 0. + + See also: + sizeof, + allocate_mapping + diff -c -r --new-file ds1.1/lib/doc/efun/all/allocate_buffer ds2.1/lib/doc/efun/all/allocate_buffer *** ds1.1/lib/doc/efun/all/allocate_buffer Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/allocate_buffer Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + allocate_buffer - allocate a buffer + + buffer allocate_buffer( int size ); + + This efun is only available if DISALLOW_BUFFER_TYPE is not compiled in. + + Allocate a buffer of 'size' elements. The number of elements must be >= 0 + and not bigger than a system maximum (usually ~10000). All elements are + initialized to 0. + + See also: + bufferp, + read_buffer, + write_buffer + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/allocate_mapping ds2.1/lib/doc/efun/all/allocate_mapping *** ds1.1/lib/doc/efun/all/allocate_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/allocate_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + allocate_mapping - pre-allocate space for a mapping + + mapping allocate_mapping( int size ); + + Returns a mapping with space for 'size' elements preallocated. + + For example: + + <pre> + mapping x; + int y = 200; + + x = allocate_mapping(y); + </pre> + + where y is the initial size of the mapping. Using allocate_mapping is + the preferred way to initalize the mapping if you have some idea of how + many elements the map will contain (200 in this case). The reason is that + allocating storage all at once is slightly more efficient. Thus if + you are using mappings to store a soul with 200 entries, the above + initialization would be quite appropriate. Note, that the + above initialization does not restrict you to 200 entries. + + See also: + map_delete + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/arrayp ds2.1/lib/doc/efun/all/arrayp *** ds1.1/lib/doc/efun/all/arrayp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/arrayp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + arrayp - determine whether or not a given variable is an array + + int arrayp( mixed arg ); + + Return 1 if `arg' is an array, zero otherwise. + + See also: + typeof diff -c -r --new-file ds1.1/lib/doc/efun/all/asin ds2.1/lib/doc/efun/all/asin *** ds1.1/lib/doc/efun/all/asin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/asin Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + asin - return the arcsine of a float + + float asin( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the arcsine of its argument, `f', measured in radians. + + See also: + acos, + atan, + cos, + sin, + tan diff -c -r --new-file ds1.1/lib/doc/efun/all/atan ds2.1/lib/doc/efun/all/atan *** ds1.1/lib/doc/efun/all/atan Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/atan Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + atan - return the tangent of a float + + float atan( float f ); + + This efun is only available if PACKAGE_MATH is not compiled in. + + Returns the arctangent of its argument, `f', measured in radians. + + See also: + acos, + asin, + cos, + sin, + tan diff -c -r --new-file ds1.1/lib/doc/efun/all/author_stats ds2.1/lib/doc/efun/all/author_stats *** ds1.1/lib/doc/efun/all/author_stats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/author_stats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,43 ---- + author_stats - returns statistics gathered on authors + + mapping author_stats( string domain); + + This efun is only avaiable if PACKAGE_MUDLIB_STATS is compiled in. + + Both domain_stats() and author_stats() return information stored in a + mapping. If no argument is specified, then information is returned on + all domains (or on all authors) with one map entry per domain or author. + If an argument is specified, then a map is returned that corresponds to + that domain or author with keys: moves, cost, errors, heart_beats, + array_size, and objects. Each of these map to integer values. + Moves is the number of objects that have moved into objects in the + given domain. Cost is the number of evaluations (eval_cost) accumulated + by objects with the given domain (or author). Errors is the number of errors + incurred by objects with the given domain. Heart_beats is the number of + heartbeat calls made on objects having the given domain. + Array_size is the size (in bytes) of the arrays allocated by the domain. + Objects is the number of objects created by the given domain. When called + with no arguments, the returned mapping has a form like this: + + <pre> + ([ domain0 : info0, domain1 : info1, ... ]) + </pre> + + while info0 has the form: + + <pre> + ([ "moves" : moves, "cost" : cost, "errors" : errors, + "heart_beats" : heart_beats, "worth" : worth, + "array_size" : array_size, "objects" : objects ]) + </pre> + + When called with an argument, the returned mapping will have the form of + info0. + + See also: + domain_file, + author_file, + set_author + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/bind ds2.1/lib/doc/efun/all/bind *** ds1.1/lib/doc/efun/all/bind Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/bind Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + bind - bind a function pointer to a new object + + function bind(function, object); + + bind() causes a function to become owned by the new object. This changes + the value of this_object() when the function pointer is evaluated. Functions + that reference global variables or functions in the object that created + them cannot be rebound. Binding a function to the object it is already + bound to will never fail. + + Permission to use this efun is controlled by the valid_bind() master apply. + + See also: + function_owner, + valid_bind diff -c -r --new-file ds1.1/lib/doc/efun/all/bufferp ds2.1/lib/doc/efun/all/bufferp *** ds1.1/lib/doc/efun/all/bufferp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/bufferp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + bufferp - determine whether or not a given variable is a buffer + + int bufferp( mixed arg ); + + Return 1 if `arg' is a buffer value and zero otherwise. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/cache_stats ds2.1/lib/doc/efun/all/cache_stats *** ds1.1/lib/doc/efun/all/cache_stats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/cache_stats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + cache_stats - report various driver and mudlib statistics + + string cache_stats(); + + This efun is only available if CACHE_STATS is defined in options.h at + driver build time. This efun returns a string containing a summary + of the statstics on the call_other() cache hit rate. + + See also: + opcprof, + mud_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/call_other ds2.1/lib/doc/efun/all/call_other *** ds1.1/lib/doc/efun/all/call_other Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/call_other Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,55 ---- + call_other - call a function in another object + + mixed call_other(mixed ob, string func, ...); + + mixed call_other(mixed ob, array args); + + mixed call_other(array obs, string func, ...); + + mixed call_other(array obs, array args); + + ob is either an object pointer, or a string filename (suitable for + find_object()). obs is an array of object pointers and strings. + Using an array as the first argument does a call_other for each element of + the array, and returns an array of the results. + If the array form is used for args, then the first element is the function + name, and the remainder are the arguments; e.g.: + + call_other(ob, ({ "foo", 1, 3, 5 })) + + and + + call_other(ob, "foo", 1, 3, 5) + + are equivalent. The function foo() is called in the object ob with the + arguments (1, 3, 5). The return value of call_other() is the value + returned from the foo() function. In the case of an array of objects, + the return value of call_other() is an array of the return values. + + There is a much more attractive way to do call_others; + call_other(x, "y", z, ...) is the same as: + + x->y(z, ...) + + ie, + + call_other(ob, "query_name"); + + could be written as: + + ob->query_name(); + + Writing out the call_other call is mainly used when the function name + is in a variable, i.e: + + <pre> + void do_test(string fname, int x) { + call_other(fname, "test_" + x); + } + </pre> + + An example of using an array as the first argument: + + users()->quit(); + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/call_out ds2.1/lib/doc/efun/all/call_out *** ds1.1/lib/doc/efun/all/call_out Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/call_out Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + call_out - delayed function call in same object + + int call_out( function fun, int delay, mixed arg, ... ); + + Set up a call to 'fun'. If fun is a string, it is interpreted as the + name of a function in this_object(). The call will take place 'delay' + seconds later, with the arguments 'arg' and following provided. + + Note: + Unless THIS_PLAYER_IN_CALL_OUT is defined, you can't rely on + write() or say() in 'fun' since this_player() is set to 0. + Use tell_object() instead. + + If THIS_PLAYER_IN_CALL_OUT is defined, this_player() is the same as + it was when the call_out() call was scheduled. + + The return value will be a unique integer identifying the call_out, if + CALLOUT_HANDLES is defined. This 'handle' can be passed to + remove_call_out() and find_call_out(). + + See also: + remove_call_out, + call_out_info, + find_call_out + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/call_out_info ds2.1/lib/doc/efun/all/call_out_info *** ds1.1/lib/doc/efun/all/call_out_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/call_out_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + call_out_info - get pending call_out() information + + array call_out_info(); + + Get information about all pending call outs. An array is returned, + where every item in the array consists 3 elements: the object, + the function, and the remaining delay. + + Note: due to security concerns, and the fact that call_outs may now + have an arbitrary number of arguments, the 4th element of the return + value was returned. The security concerns stem from the fact that if + the arguments where types which can be modified (arrays, mappings, + etc), obtaining them would allow them to be modified before the + function was called. It is possible this will be fixed in the + future if there is enough interest. + + See also: + call_out, + remove_call_out + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/call_stack ds2.1/lib/doc/efun/all/call_stack *** ds1.1/lib/doc/efun/all/call_stack Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/call_stack Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + call_stack - returns information about the functions involved in calling this function + + array call_stack(int); + + If the int argument is 0, call_stack() returns an array of the names of the + on the call stack, with the first one being the most recent (i.e. the + currently running program). If the int argument is 1, call_stack returns + the objects in which that program is executing. If it is 2, the name + of the functions are returned. If it is 3, the value of origin() in that + frame is returned. + + See also: + previous_object, + origin diff -c -r --new-file ds1.1/lib/doc/efun/all/capitalize ds2.1/lib/doc/efun/all/capitalize *** ds1.1/lib/doc/efun/all/capitalize Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/capitalize Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + capitalize - capitalize a string + + string capitalize( string str ); + + Convert the first character in 'str' to upper case, and return the + new string. + + See also: + lower_case + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/catch ds2.1/lib/doc/efun/all/catch *** ds1.1/lib/doc/efun/all/catch Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/catch Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + catch - catch an evaluation error + + mixed catch( mixed expr ); + + mixed catch { ... }; + + Note: catch is really a keyword and not an efun. + + The code inside the { ... } or the expression is evaluated. If there + is no error, catch() returns zero. If there is an error, a string (with + a leading '*') will be returned. + + The function throw() can also be used to immediately return any value, + except 0. + + The catch() is somewhat costly, and should not be used just anywhere. + Rather, use it at places where an error would destroy consistency. + + See also: + error, + throw, + error_handler + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/ceil ds2.1/lib/doc/efun/all/ceil *** ds1.1/lib/doc/efun/all/ceil Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/ceil Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + ceil - round a float up to the nearest integer + + float ceil( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns (as a float) the nearest integer number equal to or greater than f. + + See also: + floor, + to_int, + to_float + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/check_memory ds2.1/lib/doc/efun/all/check_memory *** ds1.1/lib/doc/efun/all/check_memory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/check_memory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + check_memory - check all allocated blocks + + string check_memory(int flag) + + returns a string describing possible memory allocation problems. If the + optional flag is 1, a summary of allocated memory is printed at the + end. + + This efun is only available if PACKAGE_DEVELOP, DEBUGMALLOC, and + DEBUGMALLOC_EXTENSIONS are defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/children ds2.1/lib/doc/efun/all/children *** ds1.1/lib/doc/efun/all/children Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/children Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + children - returns an array of objects cloned from a given file + + object array children( string name ); + + This efun returns an array of objects that have been loaded or cloned from + the file named by 'name' (including the object 'name' itself, if loaded). + + See also: + deep_inherit_list, + inherit_list, + objects + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/classp ds2.1/lib/doc/efun/all/classp *** ds1.1/lib/doc/efun/all/classp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/classp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + classp - determine whether or not a given variable is a class + + int classp(mixed); + + Return 1 if the argument is a class. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/clear_bit ds2.1/lib/doc/efun/all/clear_bit *** ds1.1/lib/doc/efun/all/clear_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/clear_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + clear_bit - zero a bit in a bit string + + string clear_bit( string str, int n ); + + Return the new string where bit 'n' is cleared in string 'str'. Note that + the old string 'str' is not modified. See set_bit() for information on + the format of the string. + + See also: + set_bit, + test_bit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/clone_object ds2.1/lib/doc/efun/all/clone_object *** ds1.1/lib/doc/efun/all/clone_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/clone_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + clone_object - load a copy of an object + + object clone_object( string name, ... ); + + object new( string name, ... ); + + Create a new object from the file 'name', and give it a new unique + name (by adding #xxx on to the end of the name). Returns the new object. + The object shares the program of the object 'name', but has its own + set of variables. The second and following arguments are passed to + create() + + See also: + destruct, + move_object, + new + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/clonep ds2.1/lib/doc/efun/all/clonep *** ds1.1/lib/doc/efun/all/clonep Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/clonep Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + clonep - determine whether or not a given variable points to a cloned object + + int clonep(); + + int clonep(mixed arg); + + Returns true (1) iff the argument is objectp() and the O_CLONE flag is set. + The driver sets the O_CLONE flag for those objects created via new() + (clone_object()). The clonep() efun will not return true when called on + objects that are the blueprint copy (those that are loaded via call_other() + or load_object()). + + Note that if clonep() returns true, then file_name() will return a string + containing a '#'. clonep() defaults to this_object(). + + See also: + objectp, + new, + clone_object, + call_other, + file_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/command ds2.1/lib/doc/efun/all/command *** ds1.1/lib/doc/efun/all/command Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/command Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + command - execute a command as if given by the object + + int command( string str ); + + This efun is only available if NO_ADD_ACTION isn't defined. + + Execute 'str' for the object this_object() as a command (matching against + add_actions and such). The object must have called enable_commands() for + this to have any effect. + In case of failure, 0 is returned, otherwise a numeric value is returned, + which is the LPC "evaluation cost" of the command. Bigger numbers mean + higher cost, but the whole scale is subjective and unreliable. + + See also: + add_action, + enable_commands diff -c -r --new-file ds1.1/lib/doc/efun/all/commands ds2.1/lib/doc/efun/all/commands *** ds1.1/lib/doc/efun/all/commands Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/commands Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + commands - returns some information about actions the user can take + + array commands(); + + This efun is only available if NO_ADD_ACTION is not defined. + + Returns an array of an array of 4 items describing the actions that + are available to this_object(). The first item is the command + itself (as passed to add_action()). The second is the set of + flags (passed to add_action as the third argument, often defaulted + to 0). The third is the object that defined the action. The fourth + is the function to be called ("<function>" if it is a function pointer). + + See also: + add_action, + enable_commands, + disable_commands diff -c -r --new-file ds1.1/lib/doc/efun/all/copy ds2.1/lib/doc/efun/all/copy *** ds1.1/lib/doc/efun/all/copy Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/copy Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + copy - recursively duplicate a value + + mixed copy(mixed); + + copy() returns a value with exactly the same value as its argument, but with + all reference types (mappings, arrays, etc) duplicated. For example: + + mapping a, b = ({ 1 }); + a = b; + a[0] = 2; + printf("%O %O\n", a, b); + + results in ({ 2 }) and ({ 2 }), while: + + mapping a, b = ({ 1 }); + a = copy(b); + a[0] = 2; + printf("%O %O\n", a, b); + + results in ({ 2 }) and ({ 1 }). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/cos ds2.1/lib/doc/efun/all/cos *** ds1.1/lib/doc/efun/all/cos Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/cos Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + cos - return the cosine of a float + + float cos( float f ); + + This efun is only available if PACKAGE_MATH is compiled into the driver. + + Returns the cosine of its argument, `f', measured in radians. + + See also: + acos, + asin, + atan, + sin, + tan + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/cp ds2.1/lib/doc/efun/all/cp *** ds1.1/lib/doc/efun/all/cp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/cp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + cp - copy a file + + int cp(string src, string dst); + + Copies the file 'src' to the file 'dst'. + + Returns 1 for success, returns -1 if the first src is unreadable, -2 if + dst is unreadable, and -3 if an i/o error occurs. + + See also: + rm, + rmdir, + rename, + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/crc32 ds2.1/lib/doc/efun/all/crc32 *** ds1.1/lib/doc/efun/all/crc32 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/crc32 Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + crc32 - compute the cycle redundancy code for a buffer or string + + int crc32( buffer | string x ); + + Computes and returns the CRC-32 code for the given buffer or string, `x'. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/crypt ds2.1/lib/doc/efun/all/crypt *** ds1.1/lib/doc/efun/all/crypt Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/crypt Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + crypt - encrypt a string + + string crypt( string str, string seed ); + + Crypt the string 'str' using the first two characters from 'seed' as + a seed. If 'seed' is 0, then random seed is used. + + The result has the first two characters as the seed. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/ctime ds2.1/lib/doc/efun/all/ctime *** ds1.1/lib/doc/efun/all/ctime Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/ctime Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + ctime - return a time string + + string ctime( int clock ); + + Gives a nice string with current date and time, with the argument 'clock' + that is the number of seconds since 1970. + + See also: + time, + localtime, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/debug_info ds2.1/lib/doc/efun/all/debug_info *** ds1.1/lib/doc/efun/all/debug_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/debug_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,93 ---- + debug_info - display debug information + + string debug_info( int operation, ... ); + + string debug_info( 0, object ob ); + + string debug_info( 1, object ob ); + + string debug_info( 2, object ob ); + + This efun is only available if PACKAGE_DEVELOP is compiled into the driver. + + debug_info() is a general-purpose facility which may be used to debug the + MudOS driver. The debugging information requested is determined by the + first argument. Successive arguments are determine by the operation selected. + + The existing operations (0 , 1 and 2) require a second object type argument, + and may be used to display the various fields of the MudOS object structure. + + The following LPC code was used to generate the sample output: + + <pre> + + create() { + write(debug_info(0, this_object())); + } + </pre> + + gives: + + <pre> + O_HEART_BEAT : FALSE + O_IS_WIZARD : FALSE + O_ENABLE_COMMANDS : FALSE + O_CLONE : FALSE + O_DESTRUCTED : FALSE + O_SWAPPED : FALSE + O_ONCE_INTERACTIVE: FALSE + O_RESET_STATE : FALSE + O_WILL_CLEAN_UP : FALSE + O_WILL_RESET: TRUE + total light : 0 + next_reset : 720300560 + time_of_ref : 720299416 + ref : 2 + swap_num : -1 + name : 'u/c/cynosure/di0' + next_all : OBJ(bin/dev/_update) + This object is the head of the object list. + </pre> + + <hr> + + <pre> + + create() { + write(debug_info(1, this_object())); + } + </pre> + + gives: + + <pre> + program ref's 1 + Name u/c/cynosure/di1.c + program size 10 + num func's 1 (16) + num strings 0 + num vars 0 (0) + num inherits 0 (0) + total size 104 + </pre> + + <hr> + + <pre> + + create() { + write(debug_info(2, this_object())); + } + </pre> + + gives: + + <pre> + x: "foo" + </pre> + + See also: + dump_file_descriptors, + dump_socket_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/debugmalloc ds2.1/lib/doc/efun/all/debugmalloc *** ds1.1/lib/doc/efun/all/debugmalloc Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/debugmalloc Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + debugmalloc - dumps information on malloc'd memory to a file + + void debugmalloc(string filename, int mask); + + This efun is only available when PACKAGE_DEVELOP, DEBUGMALLOC and DEBUGMALLOC_EXTENSIONS are + both defined in options.h at driver build time. The debugmalloc() efun + will dump information on those chunks of memory allocated by DMALLOC() and + related macros if the bitwise and (&) with the tag supplied by the macro + (i.e. (mask & tag)) is non-zero. Read md.c and config.h in the + driver source for more information. + + See also: + set_malloc_mask + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/deep_inherit_list ds2.1/lib/doc/efun/all/deep_inherit_list *** ds1.1/lib/doc/efun/all/deep_inherit_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/deep_inherit_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + deep_inherit_list - get a list of ancestors of an object + + string array deep_inherit_list( object obj ); + + Returns an array of filenames of all objects inherited (directly and + indirectly) by obj. + + See also: + inherit_list, + inherits + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/deep_inventory ds2.1/lib/doc/efun/all/deep_inventory *** ds1.1/lib/doc/efun/all/deep_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/deep_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + deep_inventory - return the nested inventory of an object + + object array deep_inventory( object ob ); + + This efun is only available when NO_ENVIRONMENT is not compiled into the + driver. + + Returns an array of the objects contained in the inventory of 'ob' and + also all the objects contained in the inventories of those objects and so on. + + See also: + all_inventory + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/destruct ds2.1/lib/doc/efun/all/destruct *** ds1.1/lib/doc/efun/all/destruct Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/destruct Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + destruct - remove an object + + void destruct( object ob ); + + Completely destroy and remove object 'ob'. After the call to destruct(). + If 'ob' is this_object(), execution will continue, but it is best to return + a value immediately. All pointers to the object in any variable or structure + will immediately become zero. move_or_destruct() is called in all the + objects inside of the object being destructed. + + See also: + clone_object, + new, + move_or_destruct + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/disable_commands ds2.1/lib/doc/efun/all/disable_commands *** ds1.1/lib/doc/efun/all/disable_commands Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/disable_commands Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + disable_commands - makes a living object non-living + + void disable_commands(); + + This efun is only available if NO_ADD_ACTION is not defined. + + Causes the current object to no longer be able to execute commands. + + See also: + enable_commands diff -c -r --new-file ds1.1/lib/doc/efun/all/disable_wizard ds2.1/lib/doc/efun/all/disable_wizard *** ds1.1/lib/doc/efun/all/disable_wizard Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/disable_wizard Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + disable_wizard - remove wizard priveleges from an object + + void disable_wizard(); + + This efun is only available if NO_WIZARDS is not defined. + + The opposite of enable_wizard(). Disables wizard privileges from the + current object. + + See also: + enable_wizard, + wizardp diff -c -r --new-file ds1.1/lib/doc/efun/all/domain_stats ds2.1/lib/doc/efun/all/domain_stats *** ds1.1/lib/doc/efun/all/domain_stats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/domain_stats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,42 ---- + domain_stats - returns statistics gathered on domains + + mapping domain_stats( string domain ); + + This efun is only available if PACKAGE_MUDLIB_STATS is compiled into the driver. + + Both domain_stats() and author_stats() return information stored in a + mapping. If no argument is specified, then information is returned on + all domains (or on all authors) with one map entry per domain or author. + If an argument is specified, then a map is returned that corresponds to + that domain or author with keys: moves, cost, errors, heart_beats, + array_size, and objects. Each of these map to integer values. + Moves is the number of objects that have moved into objects in the + given domain. Cost is the number of evaluations (eval_cost) accumulated + by objects with the given domain (or author). Errors is the number of errors + incurred by objects with the given domain. Heart_beats is the number of + heartbeat calls made on objects having the given domain. + Array_size is the size (in bytes) of the arrays allocated by the domain. + Objects is the number of objects created by the given domain. When called + with no arguments, the returned mapping has a form like this: + + <pre> + ([ domain0 : info0, domain1 : info1, ... ]) + </pre> + + while info0 has the form: + + <pre> + ([ "moves" : moves, "cost" : cost, "errors" : errors, + "heart_beats" : heart_beats, "worth" : worth, + "array_size" : array_size, "objects" : objects ]) + </pre> + + When called with an argument, the returned mapping will have the form of + info0. + + See also: + domain_file, + author_file, + set_author + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/dump_file_descriptors ds2.1/lib/doc/efun/all/dump_file_descriptors *** ds1.1/lib/doc/efun/all/dump_file_descriptors Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/dump_file_descriptors Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,32 ---- + dump_file_descriptors - dump the MudOS process file descriptor table + + string dump_file_descriptors(); + + This function is provided to assist in debugging the MudOS driver and + helps overcome deficiencies in some UN*X implementations which do not + provide equivalent or superior debugging facilities as part of the + operating system itself. The interpretation of the output is very + system-dependent. Each file descriptor is checked to determine whether + it refers to an open file. If so, information is displayed from the + "stat structure" returned by the fstat() system call. + + The following output was produced on Lambda Realms running on a Sequent + DYNIX/ptx system: + + <pre> + Fd Device Number Inode Mode Uid Gid Size + -- ------------- ----- ------ ----- ----- ---------- + 0 3 2 10319 c 666 0 3 0 + 1 79 7 164598 f 644 2862 1 789522 + 2 79 7 164598 f 644 2862 1 789522 + 3 40 33b 6925 c 0 2862 1 0 + 4 40 2a4 6943 c 0 2862 1 0 + 5 79 7 164599 f 600 2862 1 44784 + 6 40 2e2 145996 c 0 2862 1 0 + 7 79 7 164601 f 644 2862 1 506 + </pre> + + See also: + dump_socket_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/dump_prog ds2.1/lib/doc/efun/all/dump_prog *** ds1.1/lib/doc/efun/all/dump_prog Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/dump_prog Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + dump_prog - dump/disassemble an LPC object + + void dump_prog( object ob, int flags, string file ); + + This efun is only available when PACKAGE_DEVELOP is compiled into the driver. + + dump_prog() dumps information about the program of `obj' to a file, + `file', or "/PROG_DUMP" if `file' is not given. If the current object + does not have write access to the file, it fails. + + Flags can be a combination of the following values: + <DL> + * 1 - include a disassembly of the i-code + * 2 - include line number information + </DL> + + See also: + debug_info, + dumpallobj + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/dump_socket_status ds2.1/lib/doc/efun/all/dump_socket_status *** ds1.1/lib/doc/efun/all/dump_socket_status Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/dump_socket_status Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,54 ---- + dump_socket_status - display the status of each LPC socket + + string dump_socket_status(); + + This efun is only available when PACKAGE_SOCKETS is compiled into the driver. + + dump_socket_status() is a diagnostic facility which displays the current + status of all LPC sockets configured into the MudOS driver. It is useful + for debugging LPC sockets applications. Each row in the output corresponds + to a single LPC socket. The first row corresponds to LPC socket descriptor 0, + the second row, 1, etc. The total number of sockets is configured when the + driver is built. + + The first column "Fd" is the operating system file descriptor associated + with the LPC socket. "State" is the current operational state of the LPC + socket. "Mode" is the socket mode, which is passed as an argument to + socket_create(). The local and remote addresses are the Internet address + and port numbers in Internet dot notations. '*' indicates an address or + which is 0. N.B. LPC sockets that are in the CLOSED state are not + currently in use; therefore the data displayed for that socket may be + idiosyncratic. + + The following output was generated on Portals, where the only socket + application running at the time was MWHOD. It indicates that two + sockets are current in use, one is listening for connection requests + on a STREAM mode socket. The other is waiting for incoming data on + a DATAGRAM mode socket. + + <pre> + Fd State Mode Local Address Remote Address + -- --------- -------- ----------------- ------------------ + 13 LISTEN STREAM *.6889 *.* + 14 BOUND DATAGRAM *.6888 *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + </pre> + + See also: + debug_info, + dump_file_descriptors + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/dumpallobj ds2.1/lib/doc/efun/all/dumpallobj *** ds1.1/lib/doc/efun/all/dumpallobj Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/dumpallobj Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + dumpallobj - report various statistics on all objects that have been loaded + + void dumpallobj(); + + void dumpallobj( string ); + + This function dumps a list of statistics on all objects that have been loaded. + If no argument is specified, then the information will be dumped to a file + named /OBJ_DUMP. If an argument is specified, then that name is used as + the filename for the dump. + + See also: + mud_status, + debug_info + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/ed ds2.1/lib/doc/efun/all/ed *** ds1.1/lib/doc/efun/all/ed Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/ed Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,39 ---- + ed - edit a file + + This efun is only available if OLD_ED is defined. + + void ed( string file, string exit_fn, int restricted ); + + void ed( string file, string write_fn, string exit_fn, int restricted ); + + This is a funny function. It will start a local editor on an optional + file. This editor is almost UNIX ed compatible. When in the editor + type 'h' for help. + + The 'write_fn' function allows the mudlib to handle file locks and + administrative logging of files modified. When the editor writes to a + file, the driver will callback the 'write_fn' function twice. The first + time, the function is called before the + write takes place -- 'flag' will be 0. If the function returns 1, + the write will continue, + otherwise it will abort. The second time, the function is called + after the write has completed -- 'flag' will be non-zero. + This callback function should have the form: + + int write_fn(string fname, int flag) + + When the editor is exited, the driver will callback the 'exit_fn' + function. This function allows the mudlib to clean up. This + callback function has the form: + + void exit_fn() + + The optional 'restricted' flag limits the editor's + capabilities, such as inserting a file, and saving using an alternate + file name. + + See also: + regexp, + valid_read, + valid_write, + get_save_file_name diff -c -r --new-file ds1.1/lib/doc/efun/all/ed_cmd ds2.1/lib/doc/efun/all/ed_cmd *** ds1.1/lib/doc/efun/all/ed_cmd Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/ed_cmd Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + ed_cmd - perform an 'ed' command + + This efun is only available if OLD_ED is not defined. + + string ed_cmd(string cmd); + + Performs the ed command 'cmd'. The result of the command is returned. + Ed must have been started with ed_start() in order to call this efun. + + See also: + ed_start diff -c -r --new-file ds1.1/lib/doc/efun/all/ed_start ds2.1/lib/doc/efun/all/ed_start *** ds1.1/lib/doc/efun/all/ed_start Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/ed_start Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + ed_start - start up 'ed' + + This efun is only available if OLD_ED is not defined. + + string ed_start(string file, int flag); + + string ed_start(string file); + + string ed_start(); + + If 'flag' is nonzero, ed is started in restricted mode. See the documentation + for the old efun for information. 'file' is the name of the file to open; + if none is given then no file becomes active. + + ed_start() may not be called when another ed session for the current + object is already active. Any messages generated while starting up ed + are returned by this efun. + + See also: + ed, + ed_cmd, + query_ed_mode diff -c -r --new-file ds1.1/lib/doc/efun/all/enable_commands ds2.1/lib/doc/efun/all/enable_commands *** ds1.1/lib/doc/efun/all/enable_commands Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/enable_commands Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + enable_commands - allow object to use 'player' commands + + void enable_commands(); + + This efun is only available if NO_ADD_ACTION is not defined. + + enable_commands() marks this_object() as a living object, and allows + it to use commands added with add_action() (by using command()). + When enable_commands() is called, the driver also looks for the + local function catch_tell(), and if found, it will call it every time + a message (via say() for example) is given to the object. + + See also: + living, + add_action, + command, + catch_tell, + say diff -c -r --new-file ds1.1/lib/doc/efun/all/enable_wizard ds2.1/lib/doc/efun/all/enable_wizard *** ds1.1/lib/doc/efun/all/enable_wizard Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/enable_wizard Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,29 ---- + enable_wizard - give wizard priveleges to an object + + void enable_wizard(); + + Available only if NO_WIZARDS isn't defined. + + Any interactive object that calls enable_wizard() will cause wizardp() + to return true if called on that object. enable_wizard() gives three + privileges to the interactive object in question: + + <DL> + * ability to use restricted modes of ed when the RESTRICTED_ED option + is compiled into the driver. + * + privilege of receiving descriptive runtime error messages. + * + privilege of using the trace() and traceprefix() efuns. + <DL> + + If you don't use this, ed() must be explicitly restricted when necessary, + an error_handler should be implemented to give appropriate messages if you + don't want all users to get descriptive error traces, and trace() and + traceprefix() should be restricted via simul_efuns, if necessary. + + See also: + disable_wizard, + wizardp + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/environment ds2.1/lib/doc/efun/all/environment *** ds1.1/lib/doc/efun/all/environment Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/environment Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + environment - return the environment of an object + + object environment( object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + Return the containing object (environment) of 'ob'. If no argument + is given, 'ob' defaults to this_object(). If the object is not + inside anything, zero is returned. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/error ds2.1/lib/doc/efun/all/error *** ds1.1/lib/doc/efun/all/error Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/error Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + error - generate a run-time error + + void error( string err ); + + A run-time error 'err' will be generated when error() is called. Execution + of the current thread will halt, and the trace will be recorded to the + debug log. + + See also: + catch, + throw, + error_handler + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/eval_cost ds2.1/lib/doc/efun/all/eval_cost *** ds1.1/lib/doc/efun/all/eval_cost Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/eval_cost Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + eval_cost - returns the evaluation cost remaining + + void eval_cost() + + eval_cost() returns the number of instructions that can be executed + before the driver decides it is in an infinite loop. + + See also: + set_eval_limit, + reset_eval_cost + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/evaluate ds2.1/lib/doc/efun/all/evaluate *** ds1.1/lib/doc/efun/all/evaluate Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/evaluate Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + evaluate - evaluate a function pointer + + mixed evaluate(mixed f, ...); + + If f is a function, f is called with the rest of the arguments. + Otherwise, f is returned. evaluate(f, ...) is the same as (*f)(...). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/exec ds2.1/lib/doc/efun/all/exec *** ds1.1/lib/doc/efun/all/exec Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/exec Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + exec - switches a user (interactive) connection from one object to another + + int exec( object to, object from ); + + This efunction allows the interactive link to a given object to be + moved to another object. That is, after a successful exec(to, from) + call, interactive(to) will return 1 and interactive(from) will return 0. + The player that was controlling 'from' will begin controlling 'to' following + the exec() call. Note that this is a powerful function and its use must + be restricted if you wish to attempt to have a secure mud. The proper + way to restrict the use of exec() is to make a simul_efun of the same name + and then use valid_override() to restrict the use of a simul_efun override + (i.e. efun::exec()). The exec() function returns 1 if the switch is + successful (and 0 otherwise). + + See also: + interactive, + valid_override diff -c -r --new-file ds1.1/lib/doc/efun/all/exp ds2.1/lib/doc/efun/all/exp *** ds1.1/lib/doc/efun/all/exp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/exp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + exp - find e to the power of a float + + float exp( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + exp() returns e^f. + + See also: + log, + pow, + sqrt + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/explode ds2.1/lib/doc/efun/all/explode *** ds1.1/lib/doc/efun/all/explode Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/explode Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + explode - break up a string + + string array explode( string str, string del ); + + explode() returns an array of strings, created when the string 'str' + is split into pieces as divided by the delimiter 'del'. + + EXAMPLE: + + explode(str," ") will return as an array all of the words (separated + by spaces) in the string 'str'. + + See also: + implode, + sscanf, + replace_string, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/export_uid ds2.1/lib/doc/efun/all/export_uid *** ds1.1/lib/doc/efun/all/export_uid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/export_uid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + export_uid - set the uid of another object + + int export_uid( object ob ); + + This efun is only available if PACKAGE_UIDS is compiled in. + + Set the uid of 'ob' to the effective uid of this_object(). It is + only possible when 'ob' has an effective uid of 0. + + See also: + seteuid, + getuid, + geteuid, + valid_seteuid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/external_start ds2.1/lib/doc/efun/all/external_start *** ds1.1/lib/doc/efun/all/external_start Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/external_start Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + external_start - start an external command + + int external_start(int which, string args, mixed read_cb, mixed write_cb, mixed close_cb); + + 'which' specifies which of the 5 external commands specified in + the config file to run. 'args' are the arguments to pass to the + command. The driver then starts up the specified command, and sets up + an LPC socket to communicate with the input and output of the command. + The file descriptor of the LPC socket is returned. + + See also: + time, + ctime, + localtime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/fetch_variable ds2.1/lib/doc/efun/all/fetch_variable *** ds1.1/lib/doc/efun/all/fetch_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/fetch_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + fetch_variable - set the value of a variable + + mixed fetch_variable(string); + + Return the value of the variable specified by the argument. + Note that the variable must be defined, and must be defined in this_object(). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + restore_variable, + store_variable, + restore_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/file_length ds2.1/lib/doc/efun/all/file_length *** ds1.1/lib/doc/efun/all/file_length Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/file_length Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + file_length - get the number of lines in a file + + int file_length( string file ); + + file_length() returns the number of lines in file 'file'. Size -1 + indicates that 'file' either does not exist, or that it is not + readable. Size -2 indicates that 'file' is a directory. + + Note that this efun is not particularly fast on long files, since + determining the number of lines requires reading the entire file. + + See also: + file_size, + stat, + get_dir diff -c -r --new-file ds1.1/lib/doc/efun/all/file_name ds2.1/lib/doc/efun/all/file_name *** ds1.1/lib/doc/efun/all/file_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/file_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + file_name - get the file name of an object + + string file_name( object ob ); + + file_name() returns the name of the file from which 'ob' was loaded. + If the object is a cloned object, then file_name() will not be an + actual file on disk, but will be the name of the file from which the + object was originally cloned, appended with an octothorpe (#) and the + object instance number. Object instance numbers start at 0 when the + game is booted, and increase by one for each object cloned, hence the + number is unique for each cloned object. 'ob' defaults to this_object() + if not specified. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/file_size ds2.1/lib/doc/efun/all/file_size *** ds1.1/lib/doc/efun/all/file_size Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/file_size Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + file_size - get the size of a file + + int file_size( string file ); + + file_size() returns the size of file 'file' in bytes. Size -1 + indicates that 'file' either does not exist, or that it is not + readable. Size -2 indicates that 'file' is a directory. + + See also: + file_length, + stat, + get_dir diff -c -r --new-file ds1.1/lib/doc/efun/all/filter ds2.1/lib/doc/efun/all/filter *** ds1.1/lib/doc/efun/all/filter Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/filter Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + filter - select certain elements + + mixed filter(mixed x, string fun, object ob, mixed extra, ...); + + mixed filter(mixed x, function f, mixed extra, ...); + + The (ob, fun) syntax works as if (: call_other, ob, fun :) had been passed as + f. Filter returns a new structure containing only the elements of x for which + the function returns nonzero. Currently, it can be used on arrays and + mappings. In the case of mappings, both the key and the value are passed + to the function. extra and all the following arguments are passed to the + function after the element. For example, filter(arr, fun, 2, 3) will + first call fun(arr[0], 2, 3) then fun(arr[1], 2, 3) etc. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/filter_array ds2.1/lib/doc/efun/all/filter_array *** ds1.1/lib/doc/efun/all/filter_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/filter_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + filter_array - return a selective sub-array + + array filter_array( array arr, string fun, object ob, mixed extra, ... ); + + array filter_array( array arr, function f, mixed extra, ...); + + filter_array() is really the same as the filter() efun. + + See also: + filter + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/filter_mapping ds2.1/lib/doc/efun/all/filter_mapping *** ds1.1/lib/doc/efun/all/filter_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/filter_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + filter_mapping - return a selective sub-mapping + + mapping filter_mapping(mapping map, string fun, object ob, mixed extra, ...); + + mapping filter_array(mapping map, function f, mixed extra, ...); + + filter_mapping() is really the same as the filter() efun. + + See also: + filter + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/find_call_out ds2.1/lib/doc/efun/all/find_call_out *** ds1.1/lib/doc/efun/all/find_call_out Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/find_call_out Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + find_call_out - find a call out scheduled to be called next + + int find_call_out( string func ); + + Find the first call out due to be executed for function 'func' in the + current object, or the call_out() which returned the integer 'handle', + and return the time left. If it is not found, then return -1. + + See also: + call_out, + remove_call_out, + set_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/find_living ds2.1/lib/doc/efun/all/find_living *** ds1.1/lib/doc/efun/all/find_living Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/find_living Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + find_living - find a living object matching a given id + + object find_living( string str ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Find first the object that is marked as living, and answers to the + id 'str'. A living object is an object that has called + enable_commands(). The object must have set a name with + set_living_name(), so its name will be entered into the hash table + used to speed up the search for living objects. + + See also: + living, + livings, + users, + disable_commands, + enable_commands, + set_living_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/find_object ds2.1/lib/doc/efun/all/find_object *** ds1.1/lib/doc/efun/all/find_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/find_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + find_object - find an object by file name + + object find_object( string str ); + + Find the object with the file name 'str'. If the object is a + cloned object, then it can be found using the file name which + would by returned if file_name() was called with it as the + argument. + + See also: + file_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/find_player ds2.1/lib/doc/efun/all/find_player *** ds1.1/lib/doc/efun/all/find_player Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/find_player Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + find_player - find a player by name + + object find_player( string str ); + + This efun is only available when NO_ADD_ACTION is not defined. + + Similar to find_living(), but only searches through objects that are + interactive, or were once interactive. + + See also: + find_living, + livings, + users, + set_living_name diff -c -r --new-file ds1.1/lib/doc/efun/all/first_inventory ds2.1/lib/doc/efun/all/first_inventory *** ds1.1/lib/doc/efun/all/first_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/first_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + first_inventory - return the first item in an object's inventory + + object first_inventory( mixed ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + Return the first object in the inventory of 'ob', where 'ob' is + either an object or the file name of an object. + + See also: + file_name, + next_inventory, + all_inventory, + deep_inventory + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/floatp ds2.1/lib/doc/efun/all/floatp *** ds1.1/lib/doc/efun/all/floatp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/floatp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + floatp - determine whether or not a given variable is a float + + int floatp( mixed arg ); + + Return 1 if `arg' is a float number and zero (0) otherwise. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/floor ds2.1/lib/doc/efun/all/floor *** ds1.1/lib/doc/efun/all/floor Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/floor Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + floor - round a float down to the nearest integer + + float floor( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns (as a float) the nearest integer number equal to or smaller than f. + + See also: + ceil, + to_int, + to_float diff -c -r --new-file ds1.1/lib/doc/efun/all/flush_messages ds2.1/lib/doc/efun/all/flush_messages *** ds1.1/lib/doc/efun/all/flush_messages Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/flush_messages Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + flush_messages - send all pending messages to a user + + int flush_messages(); + + int flush_messages(object user); + + Normally, messages are queued, then sent all at once to minimize the + number of packets required. This efun forces all pending messages to + be written immediately. If no user is specified, messages for ALL users + are flushed. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/function_exists ds2.1/lib/doc/efun/all/function_exists *** ds1.1/lib/doc/efun/all/function_exists Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/function_exists Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + function_exists - find the file containing a given function in an object + + string function_exists( string str, object ob, int flag ); + + Return the file name of the object that defines the function 'str' in + object 'ob'. The returned value can be other than 'file_name(ob)' if the + function is defined by an inherited object. + + 0 is returned if the function was not defined. + + Note that function_exists() does not check shadows. + + If flag is omitted or zero functions that cannot be called are not returned + (e.g. the function is returned only if call_other(ob, str) would succeed). + If the flag is nonzero, static and private functions are returned too. + + See also: + call_other + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/function_owner ds2.1/lib/doc/efun/all/function_owner *** ds1.1/lib/doc/efun/all/function_owner Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/function_owner Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + function_owner - return the owner of a given function. + + object function_owner(function); + + function_owner returns the object that owns the function specified by + the argument. + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + bind diff -c -r --new-file ds1.1/lib/doc/efun/all/function_profile ds2.1/lib/doc/efun/all/function_profile *** ds1.1/lib/doc/efun/all/function_profile Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/function_profile Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + function_profile - get function profiling information for an object + + array function_profile( object ob ); + + Returns function profiling information for 'ob', or this_object() if 'ob' + is not specified. This is only available if the driver was compiled + with PROFILE_FUNCTIONS defined. + + An array of mappings is returned, one for each function in 'ob'. The format + of the mapping is: + <pre> + ([ "name" : name_of_the_function, + "calls" : number_of_calls, + + "self" : cpu_time_spent_in self, + "children" : cpu_time_spent_in_children + ]) + </pre> + The usefulness of this is tied to the resolution of the CPU clock--even + though the units are microseconds, the CPU timer resolution is often much + less. + + See also: + rusage, + time_expression + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/functionp ds2.1/lib/doc/efun/all/functionp *** ds1.1/lib/doc/efun/all/functionp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/functionp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,49 ---- + functionp - determine whether or not a given variable is a function + pointer + + int functionp( mixed arg ); + + Return nonzero if `arg' is a function pointer and zero (0) otherwise. + Function pointers are variables of type 'function' as indicated in the + documentation for the type 'function', for example: + + f = (: call_other, obj, func :); + + The return value indicates the type of function pointer using the + values given in the driver include file "include/function.h". + + <DL> + * FP_LOCAL - lfun pointer + * FP_EFUN - efun pointer + * FP_SIMUL - simul pointer + * FP_FUNCTIONAL - functional + </DL> + + These values are bit values; the following flags may be added as well: + + <DL> + * FP_HAS_ARGUMENTS - arguments were included in the definition + * FP_OWNER_DESTED - the owner of this function pointer has been destructed + * FP_NOT_BINDABLE - it isn't possible to rebind this function pointer + </DL> + + To test if a function variable is an efun pointer: + + if (functionp(f) & FP_EFUN) ... + + to test if it is an efun or simul_efun: + + if (functionp(f) & (FP_EFUN | FP_SIMUL)) ... + + Try (very hard) to call the function: + + <pre> + if (functionp(f) & FP_OWNER_DESTED) { + if (functionp(f) & FP_NOT_BINDABLE) + error("Function could not be rebound.\n"); + f = bind(f, this_object()); + } + evaluate(f); + </pre> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/functions ds2.1/lib/doc/efun/all/functions *** ds1.1/lib/doc/efun/all/functions Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/functions Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + functions - list all the functions in a given object. + + string array functions(object, int default: 0); + + functions() can return two different things. If the second argument is + 0 (which it is by default) it will return an array containing the names + of all the functions in the object passed as the first argument. If the + second argument is non-zero, more information about each function is + given. For a non-zero second argument, each array element contains + the following: + + ({ function_name, number_of_arguments, return_type, ... }). + + Where the fourth and following elements are the argument types. If + the save_types pragma was not in effect when the function was compiled, + number_of_arguments will be correct, but no types will be available. + + This efun is only available if PACKAGE_CONTRIB is defined in the + options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/generate_source ds2.1/lib/doc/efun/all/generate_source *** ds1.1/lib/doc/efun/all/generate_source Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/generate_source Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + generate_source - generates the C code corresponding to a give object(s) + + int generate_source(string file); + + int generate_source(string array files); + + This efun is only available if LPC_TO_C is compiled into the driver. + + generate_source() calls the LPC->C compiler to generate the source code + for a given object or objects. If more than one file is passed, a directory + named 'mudlib' is created in the SAVE_BINARIES directory, and that directory + can be copied into the driver source directory and compiled into the driver. + + If one file is given, the C source for that file is compiled, and the driver + attempts to link it into the running executable using the RUNTIME_LOADING + option. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/get_char ds2.1/lib/doc/efun/all/get_char *** ds1.1/lib/doc/efun/all/get_char Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/get_char Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,28 ---- + get_char - causes next character of input to be sent to a specified function + + varargs void get_char( string | function fun, int flag, ... ); + + Enable next character of user input to be sent to the function `fun' as + an argument. The input character will not be parsed by the driver. + + Note that get_char is non-blocking which means that the object calling + get_char does not pause waiting for input. Instead the object continues + to execute any statements following the get_char. The specified function + `fun' will not be called until the user input has been collected. + + If "get_char()" is called more than once in the same execution, only the + first call has any effect. + + If optional argument `flag' is non-zero, the char given by the player will + not be echoed, and is not seen if snooped (this is useful for collecting + passwords). + + The function `fun' will be called with the user input as its first argument + (a string). Any additional arguments supplied to get_char will be passed on to + `fun' as arguments following the user input. + + See also: + call_out, + input_to + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/get_config ds2.1/lib/doc/efun/all/get_config *** ds1.1/lib/doc/efun/all/get_config Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/get_config Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + get_config - query various driver config settings + + mixed get_config( int ); + + This efun is used to query the driver's various config + settings. Please refer to the "runtime_config.h" + include file for a list of currently recognized options. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/get_dir ds2.1/lib/doc/efun/all/get_dir *** ds1.1/lib/doc/efun/all/get_dir Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/get_dir Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + get_dir - returns information pertaining to a filesystem directory + + mixed array get_dir(string dir); + + mixed array get_dir(string dir, int flag); + + If `dir' is a filename ('*' and '?' wildcards are supported), an array of + strings is returned containing all filenames that match the specification. + If `dir' is a directory name (ending with a slash--ie: "/u/", "/adm/", etc), + all filenames in that directory are returned. + + If called with a second argument equal to -1, get_dir will return an array + of subarrays, where the format of each subarray is: + + ({ filename, size_of_file, last_time_file_touched }) + + Where filename is a string and last_time_file_touched is an integer being + number of seconds since January 1, 1970 (same format as time()). The + size_of_file element is the same value that is returned by file_size(); the + size of the file in bytes, or -2 if it's a directory. + + See also: + file_size, + stat, + time, + ctime diff -c -r --new-file ds1.1/lib/doc/efun/all/geteuid ds2.1/lib/doc/efun/all/geteuid *** ds1.1/lib/doc/efun/all/geteuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/geteuid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + geteuid - return the effective user id of an object or function + + string geteuid( object|function ); + + This efun is only available if PACKAGE_UIDS is compiled into the driver. + + If given an object argument, geteuid returns the effective user id (euid) + of the object. If given an argument of type 'function', it returns the + euid of the object that created that 'function' variable. If the object, + at the time of the function variable's construction, had no euid, the + object's uid is stored instead. + + See also: + seteuid, + getuid, + export_uid, + valid_seteuid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/getuid ds2.1/lib/doc/efun/all/getuid *** ds1.1/lib/doc/efun/all/getuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/getuid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + getuid - return the user id (uid) of an object + + string getuid( object ob ); + + This efun is only available if PACKAGE_UIDS is compiled into the driver. + + Returns the user id of an object. The uid of an object is determined at + object creation by the creator_file() function. + + See also: + seteuid, + geteuid, + export_uid, + valid_seteuid, + creator_file + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/heart_beat_info ds2.1/lib/doc/efun/all/heart_beat_info *** ds1.1/lib/doc/efun/all/heart_beat_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/heart_beat_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + heart_beat_info - return an array of objects with active heartbeats + + object array heart_beat_info(); + + Returns an array of all the objects with active heart_beats. This efun + is only available if COMPAT_32 is defined. + + See also: + heart_beats.html + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/heart_beats ds2.1/lib/doc/efun/all/heart_beats *** ds1.1/lib/doc/efun/all/heart_beats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/heart_beats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + heart_beats - return an array of objects with active heartbeats + + object array heart_beats(); + + Returns an array of all the objects with active heart_beats. This efun + is only available if PACKAGE_CONTRIB is defined. + + See also: + heart_beat, + set_heart_beat, + query_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/implode ds2.1/lib/doc/efun/all/implode *** ds1.1/lib/doc/efun/all/implode Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/implode Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + implode - concatenate strings + + string implode( array arr, string del ); + + mixed implode( array arr, function f); + + mixed implode( array arr, function f, mixed start); + + Concatenate all strings found in array 'arr', with the string 'del' between + each element. Only strings are used from the array. Elements that are not + strings are ignored. + + The second version takes the first and second values of arr and passes them + to f, then passes that result and the third arg to f, et cetera. It returns + the last result of the call to f. + + In the third case, the first call is f(start, arr[0]), then things proceed + as above. + + See also: + explode, + sprintf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/in_edit ds2.1/lib/doc/efun/all/in_edit *** ds1.1/lib/doc/efun/all/in_edit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/in_edit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + in_edit() - determine if a player is in the editor + + string in_edit(); + + string in_edit(object ob); + + If the given object is in the editor, the file being edited is + returned, else zero. If no object is given, this_object() is used. + + See also: + ed, + in_input + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/in_input ds2.1/lib/doc/efun/all/in_input *** ds1.1/lib/doc/efun/all/in_input Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/in_input Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + in_input() - determines if a player is inputting to an input_to + + int in_input(); + + int in_input(object ob); + + Returns 1 if the object is currently inputting to an input_to or get_char. + If no object is specified, this_object() is assumed. + + See also: + get_char, + input_to + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/index ds2.1/lib/doc/efun/all/index *** ds1.1/lib/doc/efun/all/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,36 ---- + System efuns + + <DL> + * all_previous_objects + * call_out_info + * check_memory + * ctime + * debug_message + * deep_inherit_list + * error + * eval_cost + * external_start + * find_call_out + * flush_messages + * function_exists + * function_profile + * functions + * inherit_list + * inherits + * localtime + * lpc_info + * max_eval_cost + * memory_summary + * named_livings + * program_info + * reclaim_objects + * replace_program + * reset_eval_cost + * set_eval_limit + * set_reset + * shutdown + * time + * uptime + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/inherit_list ds2.1/lib/doc/efun/all/inherit_list *** ds1.1/lib/doc/efun/all/inherit_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/inherit_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + inherit_list - get a list of parents of an object + + string array inherit_list( object obj ); + + Returns an array of filenames of objects inherited by obj. + If COMPAT_32 was compiled in, this behaves like deep_inherit_list(), + otherwise it behaves like shallow_inherit_list(). + + See also: + deep_inherit_list, + shallow_inherit_list, + inherits + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/inherits ds2.1/lib/doc/efun/all/inherits *** ds1.1/lib/doc/efun/all/inherits Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/inherits Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + inherits - determine if an object inherits a given file + + int inherits( string file, object obj ); + + inherits() returns 0 if obj does not inherit file, 1 if it inherits the + most recent copy of file, and 2 if it inherits an old copy of file. + + See also: + deep_inherit_list, + inherit_list + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/input_to ds2.1/lib/doc/efun/all/input_to *** ds1.1/lib/doc/efun/all/input_to Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/input_to Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,33 ---- + input_to - causes next line of input to be sent to a specified function + + varargs void input_to( string | function fun, int flag, ... ); + + Enable next line of user input to be sent to the local function 'fun' as + an argument. The input line will not be parsed by the driver. + + Note that input_to is non-blocking which means that the object calling + input_to does not pause waiting for input. Instead the object continues + to execute any statements following the input_to. The specified function + 'fun' will not be called until the user input has been collected. + + If "input_to()" is called more than once in the same execution, only the + first call has any effect. + + If optional argument 'flag' has the 1 bit set, the line given by the player + will not be echoed, and is not seen if snooped (this is useful for collecting + passwords). + + If 'flag' has the 2 bit set, the input_to cannot be bypassed by beginning the + command with '!'. Otherwise, lines which start with '!' drop through to + the normal input handler. + + The function 'fun' will be called with the user input as its first argument + (a string). Any additional arguments supplied to input_to will be passed on to + 'fun' as arguments following the user input. + + See also: + call_other, + call_out, + get_char + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/interactive ds2.1/lib/doc/efun/all/interactive *** ds1.1/lib/doc/efun/all/interactive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/interactive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + interactive - detects whether or not a given object is an interactive + + int interactive( object ob ); + + Return non-zero if 'ob' is an interactive player. 0 will be returned + if he is link dead. + + See also: + query_ip_number, + query_ip_name, + enable_commands + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/intp ds2.1/lib/doc/efun/all/intp *** ds1.1/lib/doc/efun/all/intp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/intp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + intp - determine whether or not a given variable is an integer + + int intp( mixed arg ); + + Return 1 if 'arg' is an integer number and zero (0) otherwise. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/keys ds2.1/lib/doc/efun/all/keys *** ds1.1/lib/doc/efun/all/keys Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/keys Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + keys - return an array of the keys from the (key, value) pairs in a mapping + + array keys( mapping m ); + + keys() returns an array of keys (indices) corresponding to the keys in + the (key, value) pairs stored in the mapping m. + + For example, if: + + <pre> + mapping m; + m = (["hp" : 35, "sp" : 42, "mass" : 100]); + </pre> + + then + + <pre> + keys(m) == ({"hp", "sp", "mass"}) + </pre> + + Note: the keys will not be returned in any apparent order. However, they + will be returned in the same order as the corresponding values (returned + by the values() efun). + + See also: + values + diff -c -r --new-file ds1.1/lib/doc/efun/all/link ds2.1/lib/doc/efun/all/link *** ds1.1/lib/doc/efun/all/link Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/link Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + link - link a file to another + + void link( string original, string reference ); + + Creates a link 'reference' to the file 'original'. This efun causes + valid_link(original, reference) to be called in the master object. If + valid_link() returns 0, the link() call fails. If valid_link() returns 1 + then the link() suceeds iff rename() would succeed if called with the same + arguments. + + See also: + rm, + rmdir, + rename, + mkdir, + cp + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/living ds2.1/lib/doc/efun/all/living *** ds1.1/lib/doc/efun/all/living Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/living Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + living - detects whether or not a given object is "living" + + int living( object ob ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Return true if `ob' is a living object (that is, if "enable_commands()" has + been called by `ob'). + + See also: + enable_commands + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/livings ds2.1/lib/doc/efun/all/livings *** ds1.1/lib/doc/efun/all/livings Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/livings Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + livings - return an array of all living objects + + object array livings(); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Returns an array of pointers to all living objects (objects that have + had enable_commands() called in them). + + See also: + enable_commands, + find_living, + users + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/load_object ds2.1/lib/doc/efun/all/load_object *** ds1.1/lib/doc/efun/all/load_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/load_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + load_object - find or load an object by file name + + object load_object( string str ); + + Find the object with the file name 'str'. If the object is already + loaded, it is returned (just like find_object()). If the file exists + and the object hasn't been loaded yet, it is loaded first, then the + new object is returned. Otherwise zero is returned. An error is + thrown only if the object has compile errors. + + See also: + file_name, + find_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/localtime ds2.1/lib/doc/efun/all/localtime *** ds1.1/lib/doc/efun/all/localtime Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/localtime Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,38 ---- + localtime - convert to local time + + array localtime( int time ); + + localtime() converts a time value (as returned by time()) into an array + of values which represents the time locally. In the past time() was used + to get the time in GMT (UTC), and then local definitions were used to + determine the local offset from GMT. This roundabout approach is no + longer necessary. localtime() returns the seconds, minutes and hours, + the day, month and year, day of the week, day of the year, + the name of the local timezone and how far the MUD is from GMT. This + information is retrieved directly from the operating system and made + available to the driver without the use of MUD-specific configuration + files. + + localtime() returns an array containing the values specified above. + The index for each value is defined symbolically in localtime.h. The + following table summarizes the array returned by localtime(). + <pre> + int LT_SEC Seconds after the minute (0..59) + int LT_MIN Minutes after the hour (0..59) + int LT_HOUR Hour since midnight (0..23) + int LT_MDAY Day of the month (1..31) + int LT_MON Months since January (0..11) + int LT_YEAR Year (guarenteed to be >= 1900) + int LT_WDAY Days since Sunday (0..6) + int LT_YDAY Days since January 1 (0..365) + int LT_GMTOFF Seconds after GMT (UTC) + string LT_ZONE Timezone name + </pre> + + See also: + ctime, + time, + time_expression, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/log ds2.1/lib/doc/efun/all/log *** ds1.1/lib/doc/efun/all/log Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/log Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + log - returns the natural logarithm of a float + + float log( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the natural logarithm of its argument, `f'. `f' must be positive. + + See also: + exp, + pow, + sqrt diff -c -r --new-file ds1.1/lib/doc/efun/all/lower_case ds2.1/lib/doc/efun/all/lower_case *** ds1.1/lib/doc/efun/all/lower_case Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/lower_case Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + lower_case - return the lowercase version of a given string + + string lower_case( string str ); + + Return the lowercase version of a given string (original string remains + unchanged). + + See also: + capitalize + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/lpc_info ds2.1/lib/doc/efun/all/lpc_info *** ds1.1/lib/doc/efun/all/lpc_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/lpc_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + lpc_info - return information about LPC->C compiled objects + + string lpc_info(); + + lpc_info() returns a string describing which LPC->C programs are available, + which are loaded, and which are out of date with respect to their source. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/m_delete ds2.1/lib/doc/efun/all/m_delete *** ds1.1/lib/doc/efun/all/m_delete Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/m_delete Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,28 ---- + m_delete - remove a key from a mapping + + mapping m_delete(mapping m, mixed element); + + This efun is only available if COMPAT_32 is defined. + + It behaves exactly like map_delete(), except that it returns its first + argument. + + Note: the 3.2 version actually returns a copy of the mapping, + so for strict compatibility the following simul is suggested: + + <pre> + mapping m_delete(mapping m, mixed element) + { + mapping ret = copy(m); + map_delete(ret, element); + return ret; + } + </pre> + + However, this version is significantly faster as it avoids the copy. + + See also: + map_delete + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/m_indices ds2.1/lib/doc/efun/all/m_indices *** ds1.1/lib/doc/efun/all/m_indices Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/m_indices Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + m_indices - return the keys of a mapping + + array m_indices(mapping); + + This efun is only available if COMPAT_32 is defined. It behaves exactly + the same as keys(). + + See also: + keys + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/m_values ds2.1/lib/doc/efun/all/m_values *** ds1.1/lib/doc/efun/all/m_values Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/m_values Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + m_values - return the values of a mapping + + array m_values(mapping); + + This efun is only available if COMPAT_32 is defined. It behaves exactly + the same as values(). + + See also: + values + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/malloc_status ds2.1/lib/doc/efun/all/malloc_status *** ds1.1/lib/doc/efun/all/malloc_status Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/malloc_status Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + malloc_status - report various statistics related to memory usage. + + string malloc_status(); + + This function returns memory usage statistics in a string. + This function replaces the hardcoded 'malloc' command in vanilla 3.1.2. + Note that the output produced by malloc_status() depends upon which + memory management package is chosen in options.h when building the driver. + + See also: + mud_status, + dumpallobj, + memory_info + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/map ds2.1/lib/doc/efun/all/map *** ds1.1/lib/doc/efun/all/map Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/map Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + map - modify an mapping + + mixed map( mixed x, string fun, object ob, mixed extra, ... ); + + mixed map( mixed x, function f, mixed extra, ... ); + + The (ob, fun) syntax works as if (: call_other, ob, fun :) had been passed as + f. Map returns a new structure containing the return values of f being applied + to each element of x. Currently, it can be used on arrays, mappings and + strings. In the case of mappings, both the key and the value are passed + to the function. In the case of strings, the characters are passed to the + function one at a time as ints. extra and all the following arguments are + passed to the function after the element. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/map_array ds2.1/lib/doc/efun/all/map_array *** ds1.1/lib/doc/efun/all/map_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/map_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + map_array - modify an array of elements via application of a function + + array map_array( array arr, string fun, object ob, mixed extra, ... ); + + array map_array( array arr, function f, mixed extra, ... );; + + The map_array() efun is really just an alias for the map() efun. + + See also: + map diff -c -r --new-file ds1.1/lib/doc/efun/all/map_delete ds2.1/lib/doc/efun/all/map_delete *** ds1.1/lib/doc/efun/all/map_delete Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/map_delete Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,34 ---- + map_delete - remove a (key, value) pair from a mapping based on the key + + void map_delete( mapping m, mixed element ); + + map_delete removes the (key, value) from the mapping m that has key equal + to element. + + For example, given: + + <pre> + mapping names; + + names = ([]); + names["truilkan"] = "john"; + names["wayfarer"] = "erik"; + names["jacques"] = "dwayne"; + </pre> + + Then: + <pre> + map_delete(names,"truilkan"); + </pre> + + causes the mapping 'names' to be equal to: + <pre> + (["wayfarer" : "erik", "jacques" : "dwayne"]) + </pre> + keys(names) will not contain "truilkan" after map_delete(names,"truilkan") + is called [unless ("truilkan", *) is subsequently added back to the mapping]. + + See also: + allocate_mapping + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/map_mapping ds2.1/lib/doc/efun/all/map_mapping *** ds1.1/lib/doc/efun/all/map_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/map_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + map_mapping - modify an mapping of elements via application of a function + + mapping map_mapping( mapping map, string fun, object ob, ... ); + + mapping map_mapping( mapping map, function f, ... ); + + Returns an mapping with the same keys as map whose items have been + mapped throught 'ob->fun()' or 'f'. The function is called for each + (key, value) pair in 'map' and the returned mapping has the return value + of the function as its value for each key. + The extra arguments are passed as parameters to the function + after the key and the value. + + See also: + filter_array, + filter, + sort_array, + map_array, + map + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/mapp ds2.1/lib/doc/efun/all/mapp *** ds1.1/lib/doc/efun/all/mapp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/mapp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + mapp - determine whether or not a given variable is a mapping + + int mapp( mixed arg ); + + Return 1 if `arg' is a mapping. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/master ds2.1/lib/doc/efun/all/master *** ds1.1/lib/doc/efun/all/master Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/master Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + master - returns the master object + + object master(); + + Returns a pointer to the master object. + + See also: + find_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/match_path ds2.1/lib/doc/efun/all/match_path *** ds1.1/lib/doc/efun/all/match_path Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/match_path Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + match_path - search a mapping for a path + + mixed match_path( mapping m, string str ); + + match_path() searches a mapping for a path. Each key is assumed to be a + string. The value is completely arbitrary. The efun finds the largest + matching path in the mapping. Keys ended in '/' are assumed to match paths + with character that follow the '/', i.e. / is a wildcard for anything below + this directory. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/max_eval_cost ds2.1/lib/doc/efun/all/max_eval_cost *** ds1.1/lib/doc/efun/all/max_eval_cost Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/max_eval_cost Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + max_eval_cost - returns the maximum evaluation cost + + void max_eval_cost() + + max_eval_cost() returns the number of instructions that can be executed + before the driver decides it is in an infinite loop. + + See also: + set_eval_limit, + reset_eval_cost + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/member_array ds2.1/lib/doc/efun/all/member_array *** ds1.1/lib/doc/efun/all/member_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/member_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + member_array - returns index of an occurence of a given item in an array or string + + int member_array( mixed item, mixed arr); + + int member_array( mixed item, mixed arr, int start); + + Returns the index of the first occurence of `item' in the array or string + `arr', or the first occurence at or after 'start'. + If the item is not found, then -1 is returned. + + For the purpose of this efun, strings are considered to be arrays of ints. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/memory_info ds2.1/lib/doc/efun/all/memory_info *** ds1.1/lib/doc/efun/all/memory_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/memory_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + memory_info - obtain info on object/overall memory usage + + varargs int memory_info( object ob ); + + If optional argument `ob' is given, memory_info() returns the approximate + amount of memory that `ob' is using. If no argument is given, memory_info() + returns the approximate amount of memory that the entire mud is using. Note + that the amount of memory the mud is using does not necessarily correspond + to the amount of memory actually allocated by the mud from the system, and + that total memory used by all the objects is not additive due to sharing of + certain structures. + + See also: + debug_info, + malloc_status, + mud_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/memory_summary ds2.1/lib/doc/efun/all/memory_summary *** ds1.1/lib/doc/efun/all/memory_summary Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/memory_summary Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + memory_summary - return a summary of memory usage + + mapping memory_summary(); + + memory_summary() returns a mapping of the form: + + PRE( + ([ + program name : ([ + var name : mem usage, + ... + ]) + ... + ]) + ) + + the memory usage is the memory required to store the value divided by the + number of variables pointing to that particular value. [Due to sharing + of values, giving an exact number for the memory usage of any + value is impossible] + + This efun is only available if PACKAGE_CONTRIB is defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/message ds2.1/lib/doc/efun/all/message *** ds1.1/lib/doc/efun/all/message Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/message Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,32 ---- + message - deliver messages to "living" objects + + void message( mixed class, mixed message, mixed target, mixed exclude ); + + message() calls receive_message(mixed class, mixed message) in all objects + in the target list excluding those in the exclude list. This basically + tells the object the message. + + Class is the type of message (used for clients and such). An example + would be 'combat', 'shout', 'emergency' etc. Any LPC value can be + passed, though. + + Message is usually a string containing the text to send, though it + can also be any value. + + Target is a list of objects to be sent the message. This can be either a + single object string or object pointer, or may be an array of either. + If a target is non-living all objects in its environment will receive + the message. + + Exclude is a list of objects that should not receive the message. This + can either be one object or an array of objects. + + See also: + receive_message, + say, + write, + shout, + tell_object, + tell_room + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/mkdir ds2.1/lib/doc/efun/all/mkdir *** ds1.1/lib/doc/efun/all/mkdir Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/mkdir Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + mkdir - make a directory + + int mkdir( string directory ); + + Creates the specified directory. Returns 1 if successful, 0 if not. + + See also: + rm, + rmdir, + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/move_object ds2.1/lib/doc/efun/all/move_object *** ds1.1/lib/doc/efun/all/move_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/move_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + move_object - move current object to another environment + + void move_object( mixed dest ); + + Move the current object into the object `dest'. dest should either be + a filename or an object. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/mud_status ds2.1/lib/doc/efun/all/mud_status *** ds1.1/lib/doc/efun/all/mud_status Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/mud_status Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + mud_status - report various driver and mudlib statistics + + string mud_status( int extra ); + + This function returns a string containing driver and mudlib statistics. + If extra is non-zero, then additional information about various internal + tables is included as well. This efun replaces the hardcoded 'status' + and 'status tables' commands in vanilla 3.1.2. + + See also: + debug_info, + dumpallobj, + memory_info, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/named_livings ds2.1/lib/doc/efun/all/named_livings *** ds1.1/lib/doc/efun/all/named_livings Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/named_livings Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + named_livings - return all living objects with names + + mapping named_livings(); + + named_livings() returns all objects that have called both set_living_name() + and enable_commands(). It is significantly more efficient than livings(). + + named_livings() is available if PACKAGE_CONTRIB is defined, and NO_ADD_ACTION + is not. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/new ds2.1/lib/doc/efun/all/new *** ds1.1/lib/doc/efun/all/new Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/new Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + new + + object x = new( string name, ...); + class foo x = new(class foo); + + If given a string, it behaves like clone object. If given a class type, + it creates a new instance of the class type. + + See also: + clone_object, + destruct, + move_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/next_bit ds2.1/lib/doc/efun/all/next_bit *** ds1.1/lib/doc/efun/all/next_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/next_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + next_bit - find the next bit set in a bitstring + + int next_bit( string str, int n ); + + next_bit() returns the next bit set in a bitstring after 'n', or -1 if + 'n' is the last set bit. + + See also: + set_bit, + test_bit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/next_inventory ds2.1/lib/doc/efun/all/next_inventory *** ds1.1/lib/doc/efun/all/next_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/next_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + next_inventory - return the next object in the same inventory + + object next_inventory( object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + Return the next object in the same inventory as 'ob'. + + See also: + first_inventory, + all_inventory, + deep_inventory + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/notify_fail ds2.1/lib/doc/efun/all/notify_fail *** ds1.1/lib/doc/efun/all/notify_fail Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/notify_fail Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,36 ---- + notify_fail - set the default error message to a specified string + + int notify_fail( string | function str ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Store `str' as the error message to be returned instead of the default message + `What?'. The message will be displayed if a 0 is returned from all actions + setup via add_action(). This is the preferred way to display error messages + since it allows other objects a chance to respond to the same verb (command). + Do not use write() to display the error message since this will require you + to return a 1 (unless you want to see the result of the write() in addition to + the 'What?' message). However, if you do return a 1, then no other objects + will get a chance to respond to the user command. + + Note: Getting this right in the presence of multiple failures is tricky, + to say the least. One can use a function pointer instead, and have the + routine resolve the collisions. + + If a function is passed instead of a string, the function is called + instead of printing a message. If the function returns a string, that + string is used as the failure message. Also, this_player() is set + correctly, so write() can be used. + + If "notify_fail()" is called more than once, only the last call will have + an effect. + + The idea behind this function is to allow better error messages than + `What?'. + + As a side note, notify_fail() always returns zero, so return notify_fail(...) + works as expected. + + add_action + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/nullp ds2.1/lib/doc/efun/all/nullp *** ds1.1/lib/doc/efun/all/nullp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/nullp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + nullp - determine whether or not a given variable is null + + int nullp( mixed arg ); + + Exactly the same as undefinedp(). Exists for compatibility. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/objectp ds2.1/lib/doc/efun/all/objectp *** ds1.1/lib/doc/efun/all/objectp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/objectp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + objectp - determine whether or not a given variable is an object + + int objectp( mixed arg ); + + Return 1 if `arg' is an object. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/objects ds2.1/lib/doc/efun/all/objects *** ds1.1/lib/doc/efun/all/objects Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/objects Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,25 ---- + objects - return an array of all loaded objects + + object array objects(); + + object array objects( string func, object ob ); + + object array objects( function f); + + An array of every object loaded on the mud is returned by objects(). Note + that if the system's maximum array size is set too low, objects() will + truncate its array, in which case it might not be too useful. + + If the optional `func' and `ob' parameters are given, then ob->func() + is called with each loaded object as an argument. If the function returns + nonzero, then that object is returned by objects(), otherwise it isn't. + + If 'f' is given, it will be called on all the objects as above. For + example, objects( (: clonep :) ) returns a list of all the clones in + existence. + + See also: + livings, + users + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/opcprof ds2.1/lib/doc/efun/all/opcprof *** ds1.1/lib/doc/efun/all/opcprof Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/opcprof Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + opcprof - reports statistics on calling frequencies of various efuns + + void opcprof(); + + void opcprof( string ); + + This function dumps a list of statistics on each efunction and eoperator. + If no argument is specified, then the information will be dumped to files + named /OPCPROF.efun and /OPCPROF.eoper. If an argument is specified, then + that name is used as the filename for the dump. + + See also: + function_profile + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/origin ds2.1/lib/doc/efun/all/origin *** ds1.1/lib/doc/efun/all/origin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/origin Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + origin - determine how the current function was called + + string origin(); + + Returns an string specifying how the current function was called. These + values can be found in the driver include "origin.h". Current values are: + + <DL> + * "driver" - from the driver: applies, heart_beats, etc + * "local" - local function call + * "call_other" - call_other + * "simul" - use of a simul_efun + * "call_out" - via a call_out + * "efun" - from an efun that takes a function pointer (sort_array, etc) + </DL> + + See also: + previous_object diff -c -r --new-file ds1.1/lib/doc/efun/all/pluralize ds2.1/lib/doc/efun/all/pluralize *** ds1.1/lib/doc/efun/all/pluralize Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/pluralize Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + pluralize - returns the plural of a given string + + string pluralize( string str ); + + Returns the plural of 'str'. Handles most of the oddities of the English + language. + + This efun is only available if PACKAGE_CONTRIB is defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/pointerp ds2.1/lib/doc/efun/all/pointerp *** ds1.1/lib/doc/efun/all/pointerp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/pointerp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + pointerp - determine whether or not a given variable is an array + + int pointerp( mixed arg ); + + pointerp() is provided for compatibility; it is the same as the arrayp() efun. + + See also: + arrayp diff -c -r --new-file ds1.1/lib/doc/efun/all/pow ds2.1/lib/doc/efun/all/pow *** ds1.1/lib/doc/efun/all/pow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/pow Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + pow - find an exponent of a float + + float pow( float x, float y ); + + This efun is only available if PACKAGE_MATH is defined. + + pow() returns x to the y power. If x is 0.0, y must be positive. If x is + negative, y must be an integer. + + See also: + exp, + log, + sqrt diff -c -r --new-file ds1.1/lib/doc/efun/all/present ds2.1/lib/doc/efun/all/present *** ds1.1/lib/doc/efun/all/present Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/present Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + present - find an object by id + + object present( mixed str); + + object present( mixed str, object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + If an object for which id(str) returns true exists, return it. + + `str' can also be an object, in 'str' is searched for, instead of calling + the function id(). + + If `ob' is given, then the search is done in the inventory of `ob', otherwise + the object is searched for in the inventory of the current object, and + in the inventory of the environment of the current object. + + See also: + move_object, + environment + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/previous_object ds2.1/lib/doc/efun/all/previous_object *** ds1.1/lib/doc/efun/all/previous_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/previous_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + previous_object - returns the object(s) that called the current function + + object previous_object(); + mixed previous_object(int x); + + Returns an object pointer to the object, if any, that called current function. + Note that local function calls do not set previous_object() to the current + object, but leave it unchanged. If passed a positive integer, it goes back + the given number of previous objects in the calling chain. + previous_object(0) is the same as previous_object(), previous_object(1) is + the previous object's previous_object(), etc. previous_object(-1) returns + an array containing all of the previous objects. + + See also: + call_other, + call_out, + origin + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/printf ds2.1/lib/doc/efun/all/printf *** ds1.1/lib/doc/efun/all/printf Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/printf Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,75 ---- + printf - formatted output conversion + + void printf( string format, ... ); + + The output is sent to this_user(), in the same manner as the write() efun. + Implemented by Lynscar (Sean A Reith). + + This version supports the following as modifiers: + <DL> + * " " - pad positive integers with a space. + * "+" - pad positive integers with a plus sign. + * "-" - left adjusted within field size. + + Note: std (s)printf() defaults to right justification, which is unnatural + in the context of a mainly string based language but has been retained for + "compatability". + * "|" - centered within field size. + * "=" - column mode if strings are greater than field size. This is only + meaningful with strings, all other types ignore this. Columns are + auto-magically word wrapped. + * "#" - table mode, print a list of '\\n' separated 'words' in a + table within the field size. only meaningful with strings. + * a number - + specifies the field size, a '*' specifies to use the corresponding + arg as the field size. If n is prepended with a zero, then is padded + zeros, else it is padded with spaces (or specified pad string). + * "." followed by a number - + precision of n, simple strings truncate after this (if precision is + greater than field size, then field size = precision), tables use + precision to specify the number of columns (if precision not specified + then tables calculate a best fit), all other types ignore this. + * ":" followed by a number - + n specifies the fs _and_ the precision, if n is prepended by a zero + then it is padded with zeros instead of spaces. + * "@" - + the argument is an array. the corresponding format_info (minus the + "@") is applyed to each element of the array. + * "'X'" - + The char(s) between the single-quotes are used to pad to field + size (defaults to space) (if both a zero (in front of field + size) and a pad string are specified, the one specified second + overrules). NOTE: to include "'" in the pad string, you must + use "\'" (as the backslash has to be escaped past the + interpreter), similarly, to include "\" requires "\\\\". + </DL> + + The following are the possible type specifiers. + <DL> + * % - + in which case no arguments are interpreted, and a "%" is inserted, and + all modifiers are ignored. + * O - + the argument is an LPC datatype. The format is suitable for printing any + type (useful for debugging) + * s - + the argument is a string. + * d or i - + the integer arg is printed in decimal. + * c - + the integer arg is to be printed as a character. + * o - + the integer arg is printed in octal. + * x - + the integer arg is printed in hex. + * X - + the integer arg is printed in hex (with A-F in capitals). + * f - + floating point number + </DL> + + See also: + sscanf, + sprintf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/program_info ds2.1/lib/doc/efun/all/program_info *** ds1.1/lib/doc/efun/all/program_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/program_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + program_info - returns information about program memory usage + + string program_info(); + + string program_info(object ob); + + Returns a summary of the memory usage of the program for a given object. + If no program is specified, a summary of the memory usage of all loaded + programs is returned. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_ed_mode ds2.1/lib/doc/efun/all/query_ed_mode *** ds1.1/lib/doc/efun/all/query_ed_mode Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_ed_mode Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + query_ed_mode - return which mode ed is in + + This efun is only available if OLD_ED is not defined. + + int query_ed_mode(); + + Return value should be interpreted as follows: + + 0 = normal ed prompt + + -1 = not in ed + + -2 = more prompt for help + + positive number = prompt for input for line n + + See also: + ed, + ed_start + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_heart_beat ds2.1/lib/doc/efun/all/query_heart_beat *** ds1.1/lib/doc/efun/all/query_heart_beat Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_heart_beat Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + query_heart_beat() - query the status of an object's heartbeat + + int query_heart_beat( object ); + + Returns the value with which set_heart_beat() has been called with on + 'object'. If object is not given, it defaults to the current object. If + the object has no heart beat, 0 will be returned. + + See also: + heart_beat, + set_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_host_name ds2.1/lib/doc/efun/all/query_host_name *** ds1.1/lib/doc/efun/all/query_host_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_host_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + query_host_name - return the host name + + string query_host_name(); + + query_host_name() returns the name of the host. + + See also: + resolve, + socket_address, + query_ip_name, + query_ip_number + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_idle ds2.1/lib/doc/efun/all/query_idle *** ds1.1/lib/doc/efun/all/query_idle Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_idle Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + query_idle - determine how many seconds an interactive player has been idle + + int query_idle( object ob ); + + Query how many seconds a player object (ob) has been idling. + + See also: + in_edit, + in_input + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_ip_name ds2.1/lib/doc/efun/all/query_ip_name *** ds1.1/lib/doc/efun/all/query_ip_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_ip_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + query_ip_name - return the ip name of a given player object. + + string query_ip_name( object ob ); + + Return the IP address for player `ob'. An asynchronous process `addr_server' + is used to find out these name in parallel. If there are any failures to + find the ip-name, then the ip-number is returned instead. + + See also: + query_ip_number, + query_host_name, + resolve, + socket_address + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_ip_number ds2.1/lib/doc/efun/all/query_ip_number *** ds1.1/lib/doc/efun/all/query_ip_number Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_ip_number Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + query_ip_number - return the ip number for a player object + + string query_ip_number( object ob ); + + Return the ip-number (dotted decimal form) for player `ob'. + + See also: + query_ip_name, + query_host_name, + resolve, + socket_address + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_ip_port ds2.1/lib/doc/efun/all/query_ip_port *** ds1.1/lib/doc/efun/all/query_ip_port Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_ip_port Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + query_ip_port - return the ip port of a given player object. + + int query_ip_port(object | void); + + Returns the local port that the argument object used to connect to + the mud. If the argument is void, return the local port that + this_player() used to connect to the mud. Calling this on + non-interactive objects will return 0. + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + query_ip_name, + query_host_name, + resolve, + socket_address + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_load_average ds2.1/lib/doc/efun/all/query_load_average *** ds1.1/lib/doc/efun/all/query_load_average Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_load_average Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + query_load_average - forces an error to occur in an object + + string query_load_average(); + + This function returns a string which reports two things: 1) user commands + per second, and 2) compiled lines per second. + + See also: + rusage + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_notify_fail ds2.1/lib/doc/efun/all/query_notify_fail *** ds1.1/lib/doc/efun/all/query_notify_fail Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_notify_fail Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + query_notify_fail - Query if an interactive object has a pending notify_fail() + + mixed query_notify_fail(void); + + This function returns whatever this_player()'s notify_fail value + has been set to. This is either a string, or a function, depending + on what it has been set to by the most recent call to notify_fail() + that applied to this_player(). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + This function also requires that the NO_ADD_ACTION option NOT be defined. + + See also: + add_action, + notify_fail + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_privs ds2.1/lib/doc/efun/all/query_privs *** ds1.1/lib/doc/efun/all/query_privs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_privs Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + query_privs - return the privs string for an object + + string query_privs( object ob ); + + Returns the privs string for an object. The privs string is determined + at compile time via a call to privs_file() in the master object, and changeable + via the set_privs() efun. + + This efun is only available if PRIVS is defined at driver compile time. + + See also: + privs_file, + set_privs + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/query_shadowing ds2.1/lib/doc/efun/all/query_shadowing *** ds1.1/lib/doc/efun/all/query_shadowing Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_shadowing Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + query_shadowing - determine whether or not a given object it shadowing another + + object query_shadowing( object ob ); + + This efun is only available if NO_SHADOWS is not compiled in. + + Returns the object that `ob' is shadowing, or zero (0) if it is not + shadowing any object. + + See also: + shadow, + valid_shadow + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_snoop ds2.1/lib/doc/efun/all/query_snoop *** ds1.1/lib/doc/efun/all/query_snoop Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_snoop Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + query_snoop - return the snooper of an interactive object + + object query_snoop( object ob ); + + If `ob' (an interactive object) is being snooped by another interactive object, + the snooping object is returned. Otherwise, 0 is returned. + + See also: + snoop, + query_snooping diff -c -r --new-file ds1.1/lib/doc/efun/all/query_snooping ds2.1/lib/doc/efun/all/query_snooping *** ds1.1/lib/doc/efun/all/query_snooping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_snooping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + query_snooping - return the object than an object is snooping + + object query_snooping( object ob ); + + If `ob' (an interactive object) is snooping another interactive object, the + snooped object is returned. Otherwise, 0 is returned. + + See also: + snoop, + query_snoop + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/query_verb ds2.1/lib/doc/efun/all/query_verb *** ds1.1/lib/doc/efun/all/query_verb Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/query_verb Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + query_verb - return the name of the command currently being executed + + string query_verb(); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Give the name of the current command, or 0 if not executing from a command. + This function is useful when several commands (verbs) may cause the same + function to execute and it is necessary to determine which verb it was + that invoked the function. + + See also: + add_action + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/random ds2.1/lib/doc/efun/all/random *** ds1.1/lib/doc/efun/all/random Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/random Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + random - return a pseudo-random number + + int random( int n ); + + Return a pseudo-random number from the range [0 .. (n -1)] (inclusive). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/read_buffer ds2.1/lib/doc/efun/all/read_buffer *** ds1.1/lib/doc/efun/all/read_buffer Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/read_buffer Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + read_buffer - read from a file and return a buffer + + mixed read_buffer( mixed src, int start, int len); + + This efun is only available if DISALLOW_BUFFER_TYPE is not compiled in. + + If 'src' is a string (filename), then the filename will be read, starting + at byte # 'start', for 'len' bytes, and returned as a buffer. If neither + argument is given, the entire file is read. + + If 'src' is a buffer, then characters are read from the buffer beginning + at byte # 'start' in the buffer, and for 'len' # of bytes, and returned + as a string. + + Note that the maximum number of bytes you can read from a file and into + a buffer is controlled via the 'maximum byte transfer' parameter in the + runtime config file. + + See also: + write_buffer, + allocate_buffer, + bufferp, + read_bytes, + write_bytes + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/read_bytes ds2.1/lib/doc/efun/all/read_bytes *** ds1.1/lib/doc/efun/all/read_bytes Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/read_bytes Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + read_bytes - reads a contiguous series of bytes from a file into a string + + string read_bytes( string path, int start, int length ); + + This function reads 'length' bytes beginning at byte # 'start' in the + file named 'path'. The bytes are returned as a string. Note that + (start + length) must not be past the end of the file or else read_bytes + will fail. If the second and third arguments are omitted, the entire file + is returned. + + See also: + read_file, + write_bytes diff -c -r --new-file ds1.1/lib/doc/efun/all/read_file ds2.1/lib/doc/efun/all/read_file *** ds1.1/lib/doc/efun/all/read_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/read_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + read_file - read a file into a string + + string read_file( string file, int start_line, int number_of_lines ); + + Read a line of text from a file into a string. The second and third + arguments are optional. If only the first argument is specified, the + entire file is returned (as a string). + + The start_line is the line number of the line you wish to read. This routine + will return 0 if you try to read past the end of the file, or if you try to + read from a nonpositive line. + + See also: + write_file, + read_buffer diff -c -r --new-file ds1.1/lib/doc/efun/all/receive ds2.1/lib/doc/efun/all/receive *** ds1.1/lib/doc/efun/all/receive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/receive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + receive - displays a message to the current object + + int receive( string message ); + + This efun is an interface to the add_message() function in the driver. + Its purpose is to display a message to the current object. It returns 1 + if the current object is interactive, 0 otherwise. Often, receive() is + called from within catch_tell() or receive_message(). + + See also: + catch_tell, + receive_message, + message + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/reclaim_objects ds2.1/lib/doc/efun/all/reclaim_objects *** ds1.1/lib/doc/efun/all/reclaim_objects Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/reclaim_objects Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + reclaim_objects - reclaim any lingering objects + + int reclaim_objects(); + + Cycles through all objects that are loaded, and frees any lingering objects + that it can. This could result in a sizable amount of memory being freed up, + depending on how the mud is coded. Objects are typically left lingering + when a global variable in more than one object contains a pointer to it, + and the object gets destructed, but the values containing pointers to the + object are never accessed again. This efun returns the number of destructed + objects encountered in variables. + + See also: + destruct + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/refs ds2.1/lib/doc/efun/all/refs *** ds1.1/lib/doc/efun/all/refs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/refs Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + refs - return the number of references to a data structure + + int refs( mixed data ); + + This efun is only available if PACKAGE_DEVELOP is compiled in. + + The number of references to `data' will be returned by refs(). This is + useful for deciding whether or not to make a copy of a data structure + before returning it. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/reg_assoc ds2.1/lib/doc/efun/all/reg_assoc *** ds1.1/lib/doc/efun/all/reg_assoc Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/reg_assoc Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,55 ---- + reg_assoc - A regular pattern substring extractor + + array reg_assoc(string str, string array pat_arr, array tok_arr); + + array reg_assoc(string str, string array pat_arr, array tok_arr, mixed def); + + reg_assoc() takes a string and explodes it into substrings matching + the regular expression pattern strings given in pat_arr and associates + them with tokens given in tok_arr. If def (default 0) is given, it + is associated with a non-match. The return value is an array of + two arrays, the 1st being an array of the form + <pre> + ({ non-match1, match1, non-match2, match2, ..., + non-match n, match n, non-match n+1 }) + </pre> + and the 2nd holds the tokens corresponding to the matches in order: + <pre> + ({ def, token corresponding to match1, ...., def, + token corresponding to match n, def }). + </pre> + + pat_arr and tok_arr must be of the same sizes, the ith element in + tok_arr being the corresponding token to the ith element of pat_arr. + pat_arr can only hold strings. + + If pat_arr (and hence tok_arr) has size 0 then the return value is + simply ({ ({ str }), ({ def }) }). + + EXAMPLE + + <pre> + #define STRING_PAT "\e"(\e\e\e\e.|[^\e\e\e"])*\e"" + #define NUM_PAT "[0\-9]+" + + #define F_STRING 1 + #define F_NUM 2 + + reg_assoc("Blah \e"blah\e" test 203 hhh j 308 \e"bacdcd\eb\e"acb", + ({ STRING_PAT, NUM_PAT }), ({ F_STRING, F_NUM }), "no-match") + </pre> + + will return + + <pre> + ({ ({ "Blah ", "\e"blah\e"", " test ", "203", " hhh j ", "308", " ", + "\e"bacdcd\eb\e"", "acb" }), + ({ "no-match", F_STRING, "no-match", F_NUM, "no-match", F_NUM, + "no-match", F_STRING, "no-match" }) }) + </pre> + + See also: + + regexp [for regular expression syntax] + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/regexp ds2.1/lib/doc/efun/all/regexp *** ds1.1/lib/doc/efun/all/regexp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/regexp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,93 ---- + regexp - regular expression handler + + int regexp( string str, string pattern); + + string array regexp( string array lines, string pattern); + + string array regexp( string array lines, string pattern, int flag); + + In the first version, regexp() returns true (1) if the string str contains + a substring which matches the regular expression 'pattern'. If a complete + match is wanted, the pattern should begin with ^ and end with $. + + When presented with an array of lines of text and a regular + expression, regexp() returns an array containing those lines which + match the pattern specified by the regular expression. If the (flag & 2) + is nonzero, (flag defaults to zero), then non-matches will be returned + instead of matches. If (flag & 1) is nonzero, the array returned will be of + the form ({ index1 + 1, match1, ..., indexn + 1, matchn }) where indexn + is the index of nth match/non match in the array lines. + + REGULAR EXPRESSION SYNTAX + + A regular expression is zero or more <b>branches</b>, separated by '|'. + It matches anything that matches one of the branches. + + A <b>branch</b> is zero or more <i>pieces</i>, concatenated. + It matches a match for the first, followed by a match for the second, etc. + + A <b>piece</b> is an <i>atom</i> possibly followed by '*', '+', or '?'. + An atom followed by '*' matches a sequence of 0 or more matches of the atom. + An atom followed by '+' matches a sequence of 1 or more matches of the atom. + An atom followed by '?' matches a match of the atom, or the null string. + + An <b>atom</b> is a regular expression in parentheses (matching a match for the + regular expression), a <i>range</i> (see below), '.' + (matching any single character), '^' (matching the null string at the + beginning of the input string), '$' (matching the null string at the + end of the input string), a '\e' followed by a single character (matching + that character), or a single character with no other significance + (matching that character). + + A <b>range</b> is a sequence of characters enclosed in '[]'. + It normally matches any single character from the sequence. + If the sequence begins with '^', + it matches any single character <b>not</b> from the rest of the sequence. + If two characters in the sequence are separated by '-', this is shorthand + for the full list of ASCII characters between them + (e.g. '[0-9]' matches any decimal digit). + To include a literal ']' in the sequence, make it the first character + (following a possible '^'). + To include a literal '-', make it the first or last character. + + AMBIGUITY + + If a regular expression could match two different parts of the input string, + it will match the one which begins earliest. + If both begin in the same place but match different lengths, or match + the same length in different ways, life gets messier, as follows. + + In general, the possibilities in a list of branches are considered in + left-to-right order, the possibilities for '*', '+', and '?' are + considered longest-first, nested constructs are considered from the + outermost in, and concatenated constructs are considered leftmost-first. + The match that will be chosen is the one that uses the earliest + possibility in the first choice that has to be made. + If there is more than one choice, the next will be made in the same manner + (earliest possibility) subject to the decision on the first choice. + And so forth. + + For example, '(ab|a)b*c' could match 'abc' in one of two ways. + The first choice is between 'ab' and 'a'; since 'ab' is earlier, and does + lead to a successful overall match, it is chosen. + Since the 'b' is already spoken for, + the 'b*' must match its last possibility (the empty string) since + it must respect the earlier choice. + + In the particular case where no '|'s are present and there is only one + '*', '+', or '?', the net effect is that the longest possible + match will be chosen. + So 'ab*', presented with 'xabbbby', will match 'abbbb'. + Note that if 'ab*' is tried against 'xabyabbbz', it + will match 'ab' just after 'x', due to the begins-earliest rule. + (In effect, the decision on where to start the match is the first choice + to be made, hence subsequent choices must respect it even if this leads them + to less-preferred alternatives.) + + See also: + + sscanf, + explode, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/reload_object ds2.1/lib/doc/efun/all/reload_object *** ds1.1/lib/doc/efun/all/reload_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/reload_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + reload_object - return an object to its just-loaded state + + void reload_object( object ob ); + + When reload_object() is called on `ob', all the driver-maintained properties + are re-initialized (heart_beat, call_outs, light, shadows, etc), all + variables are re-initialized, and create() is called. It has a similar + effect to destructing/reloading the object, however, no disk access or + parsing is performed. + + See also: + new, + clone_object, + destruct + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/remove_action ds2.1/lib/doc/efun/all/remove_action *** ds1.1/lib/doc/efun/all/remove_action Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/remove_action Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + remove_action - unbind a command verb from a local function + + int remove_action( string fun, string cmd ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + remove_action() unbinds a verb cmd from an object function fun. Basically, + remove_action() is the complement to add_action(). When a + verb is no longer required, it can be unbound with remove_action(). + + remove_action() returns 1 on success and 0 on failure. + + See also: + add_action, + query_verb, + init + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/remove_call_out ds2.1/lib/doc/efun/all/remove_call_out *** ds1.1/lib/doc/efun/all/remove_call_out Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/remove_call_out Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + remove_call_out - remove a pending call_out + + int remove_call_out( string fun | int handle ); + + Remove next pending call out for function `fun' in the current object, + or the call_out() which returned the integer 'handle'. + The return value is the time remaining before the callback is to be called. + The returned value is -1 if there were no call out pending to this function. + If fun is zero, all the call_outs of the object are removed. + + See also: + call_out, + call_out_info + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/remove_interactive ds2.1/lib/doc/efun/all/remove_interactive *** ds1.1/lib/doc/efun/all/remove_interactive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/remove_interactive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + remove_interactive - disconnect an interactive object. + + int remove_interactive(object); + + If the argument object is interactive, and not destructed, cause it to + be disconnected. (i.e lose it's interactive status). Returns 1 if + the operation succeeded, or 0 if it didn't ( object destructed, or not + interactive) + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/remove_shadow ds2.1/lib/doc/efun/all/remove_shadow *** ds1.1/lib/doc/efun/all/remove_shadow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/remove_shadow Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + remove_shadow - clear all the shadows related to an object. + + int remove_shadow(object); + + This function removes ALL shadows associated with the object passed + as the argument. Note this means all shadows ON the object, and all shadows + ORIGINATED by the object. + + This function requires PACKAGE_CONTRIB to be defined in the options file. + This function also requires that the option NO_SHADOWS be undefined. + + See also: + shadow + diff -c -r --new-file ds1.1/lib/doc/efun/all/rename ds2.1/lib/doc/efun/all/rename *** ds1.1/lib/doc/efun/all/rename Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/rename Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + rename - rename a file + + int rename( string src, string dst ); + + Renames the file 'src' to 'dst'. + + rename() returns zero (0) to indicate success. Nonzero indicates failure. + + See also: + rm, + rmdir, + cp, + link diff -c -r --new-file ds1.1/lib/doc/efun/all/repeat_string ds2.1/lib/doc/efun/all/repeat_string *** ds1.1/lib/doc/efun/all/repeat_string Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/repeat_string Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + repeat_string - repeat a string a specified number of times. + + string repeat_string(string, int); + + repeat_string returns a string that consists of its first argument + repeated n times, where 'n' is repeat_string's second argument. + So repeat_string("foo", 3) would return "foofoofoo". + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/replace_program ds2.1/lib/doc/efun/all/replace_program *** ds1.1/lib/doc/efun/all/replace_program Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/replace_program Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + replace_program - replaces the program in this_object() + + void replace_program( string str ); + + replace_program() replaces the program in this_object() with that of an + object it inherits. The string argument is the filename of the object + whose program is to be used. Once the replacement takes place, the current + object effectively becomes a clone of that other object, but with its + current filename and global variable values. The program is not actually + replaced until the current execution is completed. + + Note that one effect of this is that all functions defined in the object + no longer exist, being replaced by the functions in the inherited program, + so this routine should not be called if one of those functions might be + called later (and in particular, create() needs to exist if you intend to + clone from the object). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/replace_string ds2.1/lib/doc/efun/all/replace_string *** ds1.1/lib/doc/efun/all/replace_string Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/replace_string Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,47 ---- + replace_string - replace all instances of a string within a string + + string replace_string( string str, string pattern, string replace ); + + string replace_string( string str, string pattern, string replace, int max ); + + string replace_string( string str, string pattern, string replace, int first, int last ); + + replace_string() returns 'str' with all instances of 'pattern' replaced with + 'replace'. If 'pattern' has zero length then str is returned unmodified. + If the resultant string would exceed the maximum string length then + replace_string() returns an undefinedp(), non-stringp() value. + + replace_string() can be used to remove characters from a string by + specifying a pattern and a zero-length replace parameter. For example, + replace_string(" 1 2 3 ", " ", "") would return "123". replace_string() + executes faster this way then explode()/implode(). + + The 4th and 5th arguments are optional (to retain backward compatibility.) + The extra arguments have the following effect: + + With 4 args: + + The 4th argument specifies the maximum number of replacements + to make (the count starts at 1). A value of 0 implies 'replace all', and + thus, acts as replace_string() with 3 arguments would. E.g., + replace_string("xyxx", "x", "z", 2) would return "zyzx". + + With 5 args: + + The 4th and 5th arguments specify the range of matches to replace + between, with the following constraints: + + <DL> + * first < 1 : change all from the start. + * last == 0, or last > max_matches : change all to end + * first > last : return the unmodified array. + </DL> + + E.g., replace_string("xyxxy", "x", "z", 2, 3) returns "xyzzy". + + See also: + sscanf, + explode, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/replaceable ds2.1/lib/doc/efun/all/replaceable *** ds1.1/lib/doc/efun/all/replaceable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/replaceable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + replaceable - determine whether any functions are defined in at this level + + int replaceable(object ob); + + int replaceable(object ob, string array fnames); + + In the second form, return 0 if the program for object ob defines any + functions explicitly, as opposed to simply inheriting. Function names + in the array fnames are ignored. If no such functions are defined, 1 + is returned. If the second argument is omitted, it defaults to + ({ "create" }). The purpose of this efun is to assist in making + automatic decisions on whether to call replace_program(). Note that + the default version ignores create(), so it is only safe to replace a + object for which replaceable() returns true if you never intend to + clone from that object. + + See also: + replace_program, + functions, + function_exists, + inherit_list + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/reset_eval_cost ds2.1/lib/doc/efun/all/reset_eval_cost *** ds1.1/lib/doc/efun/all/reset_eval_cost Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/reset_eval_cost Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + reset_eval_cost - resets the evaluation cost remaining + + void reset_eval_cost(); + + reset_eval_cost() resets the evaluation cost remaining to the maximum + evaluation cost. + + See also: + eval_cost, + set_eval_limit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/resolve ds2.1/lib/doc/efun/all/resolve *** ds1.1/lib/doc/efun/all/resolve Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/resolve Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + resolve - resolve an internet address to domain name + + int resolve( string address, string callback_func ); + + resolve() resolves `address', which should be an internet address in the form + "127.0.0.1" or a domain name, into its domain name, or internet address. + When the resolve is complete, `callback_func' will be called in the + current object. The form of the callback is: + + void callback(string address, string resolved, int key); + + `key' will match up with the number that the call to resolve() returned. + `address' will be the domain name of the host, and `resolved' the dotted + decimal ip address. The unknown value will be 0 if the lookup failed. + + See also: + query_host_name, + socket_address, + query_ip_name, + query_ip_number + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/restore_object ds2.1/lib/doc/efun/all/restore_object *** ds1.1/lib/doc/efun/all/restore_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/restore_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + restore_object - restore values of variables from a file into an object + + int restore_object( string name, int flag ); + + Restore values of variables for current object from file `name'. If the + optional second argument is 1, then all of the non-static variables are not + zeroed out prior to restore (normally, they are). + + In the case of an error, the affected variable will be left untouched + and an error given. + + See also: + save_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/restore_variable ds2.1/lib/doc/efun/all/restore_variable *** ds1.1/lib/doc/efun/all/restore_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/restore_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + restore_variable - restore value of a variable from a string + + mixed restore_variable( string value ); + + Restores an LPC value from a string. The format used is the + same format as save/restore_object. + + See also: + save_variable, + restore_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/rm ds2.1/lib/doc/efun/all/rm *** ds1.1/lib/doc/efun/all/rm Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/rm Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + rm - remove a file + + int rm( string file ); + + Remove file `file'. Returns 0 for failure and 1 for success. + + See also: + mkdir, + rmdir, + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/rmdir ds2.1/lib/doc/efun/all/rmdir *** ds1.1/lib/doc/efun/all/rmdir Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/rmdir Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + rmdir - remove a directory + + int rmdir( string dir ); + + Remove directory `dir'. + Returns nonzero for success, zero (0) for failure. + + See also: + rm, + mkdir, + link diff -c -r --new-file ds1.1/lib/doc/efun/all/rusage ds2.1/lib/doc/efun/all/rusage *** ds1.1/lib/doc/efun/all/rusage Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/rusage Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,35 ---- + rusage - reports information gathered by the getrusage() system call + + mapping rusage(); + + This efun collects information gathered via the getrusage() system + call. Read the getrusage() man page for more information on what information + will be collected. Some systems do not have the getrusage() system call + but do have the times() system call. On those systems, only "utime" + and "stime" will be available. Times are reported in milliseconds. + + Here is an example usage of rusage(): + + <pre> + void + create() + { + mapping info; + + info = rusage(); + write("user time = " + info["utime"] + "ms\\n"); + write("system time = " + info["stime"] + "ms\\n"); + } + </pre> + + The available fields are: + utime, stime, maxrss, ixrss, idrss, isrss, minflt, majflt, nswap, inblock, + oublock, msgsnd, msgrcv, nsignals, nvcsw, nivcsw. + + See also: + time_expression, + function_profile, + time, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/save_object ds2.1/lib/doc/efun/all/save_object *** ds1.1/lib/doc/efun/all/save_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/save_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + save_object - save the values of variables in an object into a file + + int save_object( string name, int flag ); + + Save all values of non-static variables in this object in the file 'name'. + valid_write() in the master object determines whether this is allowed. + If the optional second argument is 1, then variables that are zero (0) are also + saved (normally, they aren't). Object variables and function pointers + always save as 0. save_object() returns 1 for success, 0 for failure. + + See also: + restore_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/save_variable ds2.1/lib/doc/efun/all/save_variable *** ds1.1/lib/doc/efun/all/save_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/save_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + save_variable - save the value of variable into a string + + string save_variable( mixed var ); + + Saves an LPC value into a string. The format is the same as + save/restore_object. + + See also: + restore_variable, + restore_object diff -c -r --new-file ds1.1/lib/doc/efun/all/say ds2.1/lib/doc/efun/all/say *** ds1.1/lib/doc/efun/all/say Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/say Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + say - send a message to all users in the same environment + + varargs void say( string str, object | object array ); + + Sends a message to the environment of the originator, all items in the + same environment, and all items inside of the originator. The originator + is this_player(), unless this_player() == 0, in which case, the originator + is this_object(). + + The second argument is optional. If second argument `obj' is specified, + the message is sent to all except `obj'. If `obj' is not an object, but + an array of objects, all those objects are excluded from receiving the + message. + + See also: + message, + write, + shout, + tell_object, + tell_room + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_author ds2.1/lib/doc/efun/all/set_author *** ds1.1/lib/doc/efun/all/set_author Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_author Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + set_author - set the author associated with an object + + void set_author( string author ); + + Every object has both an author and a domain associated with it for + the purposes of tracking statistics for authors and domains. Domains + may only be set in the master object function domain_file(), however + authors are different. They can be initialized to some default value + by author_file() in the master object, but can also be changed using + the set_author efun. + + set_author changes the author of the object that it is called within. + That author will get credit for all future actions of that object that + affect mudlib statistics. + + See also: + author_file, + domain_file, + author_stats, + set_author, + domain_stats + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_bit ds2.1/lib/doc/efun/all/set_bit *** ds1.1/lib/doc/efun/all/set_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_bit - set a bit in a bitstring + string set_bit( string str, int n ); + + Return the new string where bit 'n' is set in string 'str'. Note that the old string 'str' is not modified. + + The maximum value of 'n' is limited by the value of the 'maximum bits in a bitfield' entry in the driver config file. + + The new string will automatically be extended if needed. + + Bits are packed 6 per byte in printable strings. + + See also: clear_bit , test_bit + + Tim Hollebeek + Beek @ZorkMUD, Lima Bean, IdeaExchange, TMI-2, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_debug_level ds2.1/lib/doc/efun/all/set_debug_level *** ds1.1/lib/doc/efun/all/set_debug_level Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_debug_level Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + set_debug_level - sets the debug level used by the driver's debug() macro + + void set_debug_level( int level ); + + This efun is only available when the driver is compiled with -DDEBUG_MACRO. + The purpose of this efun is to allow the amount and type of debugging + information produced to be controlled from within the mud (while the + driver is running). + + For more information, read the file debug.h which is included with the + driver source. + + See also: + set_malloc_mask + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_eval_limit ds2.1/lib/doc/efun/all/set_eval_limit *** ds1.1/lib/doc/efun/all/set_eval_limit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_eval_limit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_eval_limit - set the maximum evaluation cost + + void set_eval_limit( int ); + + set_eval_limit(), with a nonzero argument, sets the maximum evaluation + cost that is allowed for any one thread before a runtime error occurs. + With a zero argument, it sets the current evaluation counter to zero, + and the maximum cost is returned. set_eval_limit(-1) returns the + remaining evaluation cost. + + See also: + eval_cost + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/set_heart_beat ds2.1/lib/doc/efun/all/set_heart_beat *** ds1.1/lib/doc/efun/all/set_heart_beat Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_heart_beat Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + set_heart_beat - enable or disable an object's heartbeat + + int set_heart_beat( int flag ); + + Passing 'flag' as 0 disables the object's heart beat. Passing a 'flag' of + 1 will cause heart_beat() to be called in the object once each heart beat + (a variable number defined by your local administrator, usually 2 seconds). + Passing a 'flag' of greater than 1 will usually set the number of heart beats + in between calls to heart_beat(), however your local administrator may have + the system configured to treat any 'flag' above 1 as 1. + + See also: + heart_beat, + query_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_hide ds2.1/lib/doc/efun/all/set_hide *** ds1.1/lib/doc/efun/all/set_hide Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_hide Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_hide - set the hide flag on a hidable object + + void set_hide( int flag ); + + Sets the hidden flag of an object to `flag', which should be 0 or 1 + (hide disable, or hide enable, respectively). Only objects for which + `master()->valid_hide(ob)' returns true may make themselves hidden. + When the object is hidden, only other hidable objects will be able to + find the object with find_object(), or multiple-object returning efuns such + as users(), children(), all_inventory(), etc. + + See also: + valid_hide + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_light ds2.1/lib/doc/efun/all/set_light *** ds1.1/lib/doc/efun/all/set_light Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_light Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + set_light - update or query an object's light level + + int set_light( int light_level_adjustment ); + + This efun is only available if NO_LIGHT is not compiled in. + + Passing 'light_level_adjustment' as 0 queries the object's current + light level. A positive number will increase the light level, while + a negative number will decrease the light level. + + Note that the object's current light level includes the light it sees from + other objects. + + This efun is provided mostly for backwards compatibility; it really should + be handled by the mudlib. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_living_name ds2.1/lib/doc/efun/all/set_living_name *** ds1.1/lib/doc/efun/all/set_living_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_living_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_living_name - set a living name for a living object + + void set_living_name( string name ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Set a living name on an object that is living. After this has been done, the + object can be found with "find_living()". + + See also: + enable_commands, + find_living, + find_player + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_malloc_mask ds2.1/lib/doc/efun/all/set_malloc_mask *** ds1.1/lib/doc/efun/all/set_malloc_mask Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_malloc_mask Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + set_malloc_mask - sets the mask controlling display of malloc debug info + + void set_malloc_mask( int mask ); + + This efun is only available when PACKAGE_DEVELOP, DEBUGMALLOC and DEBUGMALLOC_EXTENSIONS are + both defined in options.h at driver build time. The mask controls what + memory-related debugging information is displayed as the driver allocates + and deallocates memory. Read md.c in the driver source for more information. + + See also: + debugmalloc + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_privs ds2.1/lib/doc/efun/all/set_privs *** ds1.1/lib/doc/efun/all/set_privs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_privs Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_privs - set the privs string for an object + + void set_privs( object ob, string privs ); + + This efun is only available when PRIVS is compiled in. + + Sets the privs string for 'ob' to 'privs'. + + This efun is only available if PRIVS is defined at driver compile time. + + See also: + privs_file, + query_privs + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/set_reset ds2.1/lib/doc/efun/all/set_reset *** ds1.1/lib/doc/efun/all/set_reset Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_reset Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + set_reset - modify the time until reset on an object + + varargs void set_reset( object ob, int time ); + + This efun is only available if NO_RESETS is not compiled in. + + Sets the time until reset on 'ob' to 'time' seconds from now. If 'time' + is omitted, the driver's normal reset time setting formula is applied + to 'ob', that is, + <pre> + reset time = current_time + reset_time / 2 + random(reset_time / 2) + </pre> + + See also: + reset + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/set_this_player ds2.1/lib/doc/efun/all/set_this_player *** ds1.1/lib/doc/efun/all/set_this_player Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/set_this_player Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_this_player - change the value of the current command giver. + + void set_this_player(object); + + This function changes the value of what this_player() returns during the + current execution. If the argument is an object, this_player() will return + the argument object. If it is an int, this_player() will return 0. + + This function requires the NO_ADD_ACTION option be defined in the + options file. + + See also: + this_player + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/seteuid ds2.1/lib/doc/efun/all/seteuid *** ds1.1/lib/doc/efun/all/seteuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/seteuid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + seteuid - set the effective user id (euid) of an object + + int seteuid( string str ); + + This efun is only available if PACKAGE_UIDS is compiled in. + + Set effective uid to 'str'. valid_seteuid() in master.c controls which + values the euid of an object may be set to. + + When this value is 0, then the current object's uid can be changed by + export_uid(), and only then. + + But, when the value is 0, no objects can be loaded or cloned by this object. + + See also: + export_uid, + getuid, + geteuid, + valid_seteuid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/shadow ds2.1/lib/doc/efun/all/shadow *** ds1.1/lib/doc/efun/all/shadow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/shadow Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,41 ---- + shadow - shadow one or more functions in some object + + object shadow( object ob, int flag ); + + This efun is only available if NO_SHADOWS is not compiled in. + + If 'flag' is 1 or missing, then current object will shadow 'ob'. If + 'flag' is 0, then either 0 will be returned, or the object that is + already shadowing 'ob'. + + The master object defines the function "valid_shadow()". If it returns 1 + the target object can't be shadowed, and the "shadow()" function will + return 0 instead of 'ob'. + + If an object 'a' shadows an object 'b', then all "call_other(func)" to 'b' + will be redirected to 'a'. If object 'a' has not defined the function, + then the call will be forwarded to 'b' (as if there were no shadow). + There is only one object that can call functions in 'b' with + call_other(), and that is 'a'. Not even object 'b' can "call_other()" + itself. All normal (internal) function calls inside 'b' will however remain + internal to 'b'. + + There are two ways to remove the shadow. Either destruct it, or the object + that was shadowed. In the latter case, the shadow will also be destructed + automatically. Also, there is a efun remove_shadow() in the contrib package. + + The result is that it is possible to hide an object behind another one, + but everything can be totally transparent. The shadow() efunction makes + it possible to change the behavior of an object without changing the + code for the object in question. One possible use for shadow() is to + add special capabilities to various classes of players (thief, fighter, + mage, etc). This usage would make it possible to keep the player object + much simpler than it could be if the code for the various classes had + to be in the player object itself. + + See also: + destruct, + query_shadowing, + valid_shadow + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/shallow_inherit_list ds2.1/lib/doc/efun/all/shallow_inherit_list *** ds1.1/lib/doc/efun/all/shallow_inherit_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/shallow_inherit_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + shallow_inherit_list - get a list of parents of an object + + string array shallow_inherit_list( object obj ); + + Returns an array of filenames of objects inherited by obj. Only directly + inherited files are returned. E.g. if A inherits B which inherits C, + inherit_list(A) will return an array with B, but not C. + + See also: + deep_inherit_list, + inherit_list, + inherits + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/shout ds2.1/lib/doc/efun/all/shout *** ds1.1/lib/doc/efun/all/shout Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/shout Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + shout - sends a message to all living objects + + void shout( string str ); + + Sends the string `str' to all living objects except this_player(). + + See also: + message, + write, + tell_object, + tell_room, + say + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/shutdown ds2.1/lib/doc/efun/all/shutdown *** ds1.1/lib/doc/efun/all/shutdown Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/shutdown Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + shutdown - shutdown the driver + + void shutdown( int how ); + + This function shuts down the driver in a controlled fashion (as opposed to + how a crash would shut it down). The 'how' argument specifes what integer + value that driver should pass to exit(). The convention is to pass 'how' + as -1 when the script that restarts the driver should die as well. Thus + a reboot command would use shutdown() while a halt command would use + shutdown(-1). The script must explicitly check the return value to see + if it is -1 if you wish to use this convention. Obviously, shutdown() + is a sensitive function and should be secured. As with exec(), the way + to make it secure is to add a simul_efun of the same name which does + the appropriate security checks. Be sure to set valid_override() up + (in master.c) to protect against efun::shutdown(). + + See also: + crash, + slow_shutdown, + valid_override + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/sin ds2.1/lib/doc/efun/all/sin *** ds1.1/lib/doc/efun/all/sin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/sin Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + sin - return the sine of a float + + float sin( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the sine of its argument, `f', measured in radians. + + See also: + acos, + asin, + atan, + cos, + tan + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/sizeof ds2.1/lib/doc/efun/all/sizeof *** ds1.1/lib/doc/efun/all/sizeof Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/sizeof Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + sizeof - return the number of elements in an array + + int sizeof( mixed var ); + + Return the number of elements in an array, mapping, string, class or + buffer 'var'. If `var' is not an array, mapping, string, class or + buffer, then zero (0) is returned. + + See also: + strlen diff -c -r --new-file ds1.1/lib/doc/efun/all/snoop ds2.1/lib/doc/efun/all/snoop *** ds1.1/lib/doc/efun/all/snoop Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/snoop Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + snoop - snoop an interactive user + + varargs object snoop( object snooper, object snoopee ); + + When both arguments are used, begins snooping of `snoopee' by + `snooper'. If the second argument is omitted, turns off all snooping + by `snoopee'. Security for snoop() is normally controlled by a + simul_efun. snoop() returns `snoopee' if successful in the + two-argument case, and `snooper' if it was successful in the + single-argument case. A return of 0 indicates failure. + The 'snoopee' must be an interactive object; the snooper can be any + object. However, snooping with a non-interactive object is useless + unless the RECEIVE_SNOOP option is enabled, and the object defines + a RECEIVE_SNOOP function. + + See also: + query_snoop, + query_snooping + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_accept ds2.1/lib/doc/efun/all/socket_accept *** ds1.1/lib/doc/efun/all/socket_accept Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_accept Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,74 ---- + socket_accept - accept a connection on a socket + + int socket_accept( int s, string | function read_callback, string | function write_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + The argument s is a socket that has been created with socket_create(), + bound to an address with socket_bind(), and is listening for connections + after a socket_listen(). socket_accept() extracts the first connection + on the queue of pending connections, creates a new socket with the same + properties of s and allocates a new file descriptor for the socket. If no + pending connections are present on the queue, socket_accept() returns an + error as described below. The accepted socket is used to read and write data + to and from the socket which connected to this one; it is not used to accept + more connections. The original socket s remains open for accepting further + connections. + + The argument read_callback is the function or name of a function + for the driver to call when the new socket (not the accepting socket) + receives data. + + The write callback should follow this format: + + <pre> + void read_callback(int fd) + </pre> + + Where fd is the socket which is ready to accept data. + + The argument write_callback is the name of a function for the driver to + call when the new socket (not the accepting socket) is ready to be + written to. The write callback should follow this format: + + <pre> + void write_callback(int fd) + </pre> + + Where fd is the socket which is ready to be written to. + + Note: The close_callback of the accepting socket (not the new socket) + is called if the new socket closes unexpectedly, i.e. not as the result + of a socket_close() call. The close callback should follow this format: + + <pre> + void close_callback(int fd) + </pre> + + Where fd is the socket which has closed. + + socket_accept() returns a non-negative descriptor for the accepted + socket on success. On failure, it returns a negative value. socket_error() + can be used on the return value to get a text description of the error. + + ERRORS - these definitions are in socket_err.h + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEMODENOTSUPP Socket mode not supported. + * EENOTLISTN Socket not listening. + * EEWOULDBLOCK Operation would block. + * EEINTR Interrupted system call. + * EEACCEPT Problem with accept. + * EENOSOCKS No more available efun sockets. + </DL> + + See also: + socket_bind, + socket_connect, + socket_create, + socket_listen + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_acquire ds2.1/lib/doc/efun/all/socket_acquire *** ds1.1/lib/doc/efun/all/socket_acquire Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_acquire Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,32 ---- + socket_acquire - assume ownership of a socket + + int socket_acquire( int socket, string | function read_callback, + string | function write_callback, + string | function close_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_acquire() is called to complete the handshake begun by socket_release() + for transferring ownership (and control) of a socket to a new object. + socket_release() calls the release callback function within the new owner + object to notify the object that it wishes to pass control of the socket + on. It is the responsibility of the new owner socket to decide whether + it wishes to accept the socket. It it does, then socket_acquire() is + called to complete the transfer. If not, then the callback simply returns + without completing the handshake. + + In the former case the handshake is completed and the new object + becomes the socket owner. The read, write and close callback function + parameters refer to functions within the new object. These are specified + so that the MudOS driver will know which functions to call within the new + object. Decling to acquire the socket will cause socket_release() to + return EESOCKNOTRLSD so the owner can perform appropriate clean-up. + EESOCKNOTRLSD is in "socket_err.h". + + socket_acquire() may only be called within the context of thr release + callback function and only with the socket specified. + + See also: + socket_release + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_address ds2.1/lib/doc/efun/all/socket_address *** ds1.1/lib/doc/efun/all/socket_address Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_address Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + socket_address - return the remote address for an efun socket + + string socket_address( int s | object ob ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_address() returns the remote address for an efun socket s, or for + an interactive object ob. + + The returned address is of the form: + + "127.0.0.1 23". + + socket_address() returns: + + a string format address on success. + + an empty string on failure. + + See also: + socket_connect, + socket_create, + resolve, + query_host_name, + query_ip_number + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_bind ds2.1/lib/doc/efun/all/socket_bind *** ds1.1/lib/doc/efun/all/socket_bind Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_bind Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,36 ---- + socket_bind - bind a name to a socket + + int socket_bind( int s, int port ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_bind() assigns a name to an unnamed socket. When a socket is + created with socket_create() it exists in a name space (address family) + but has no name assigned. socket_bind() requests that the port be assigned + to the socket s. + + socket_bind() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - These errors are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEISBOUND Socket is already bound. + * EEADDRINUSE Address already in use. + * EEBIND Problem with bind. + * EEGETSOCKNAME Problem with getsockname. + </DL> + + See also: + socket_connect. + socket_create, + socket_listen + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_close ds2.1/lib/doc/efun/all/socket_close *** ds1.1/lib/doc/efun/all/socket_close Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_close Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + socket_close - close a socket + + int socket_close( int s ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_close() closes socket s. This frees a socket efun slot for use. + + socket_close() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + </DL> + + See also: + socket_accept, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_connect ds2.1/lib/doc/efun/all/socket_connect *** ds1.1/lib/doc/efun/all/socket_connect Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_connect Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,63 ---- + socket_connect - initiate a connection on a socket + + int socket_connect( int s, string address, + string read_callback, + string write_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + The argument s is a socket. s must be either a STREAM mode or a MUD mode + socket. address is the address to which the socket will attempt to connect. + address is of the form: "127.0.0.1 23" + + The argument read_callback is the name of a function for the driver to + call when the socket gets data from its peer. The read callback should follow + this format: + + <pre> + void read_callback(int fd, mixed message) + </pre> + + Where fd is the socket which received the data, and message is the data + which was received. + + The argument write_callback is the name of a function for the driver to + call when the socket is ready to be written to. The write callback should + follow this format: + + <pre> + void write_callback(int fd) + </pre> + + Where fd is the socket which is ready to be written to. + + socket_connect() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEMODENOTSUPP Socket mode not supported. + * EEISLISTEN Socket is listening. + * EEISCONN Socket is already connected. + * EEBADADDR Problem with address format. + * EEINTR Interrupted system call. + * EEADDRINUSE Address already in use. + * EEALREADY Operation already in progress. + * EECONNREFUSED Connection refused. + * EECONNECT Problem with connect. + </DL> + + See also: + socket_accept, + socket_close, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_create ds2.1/lib/doc/efun/all/socket_create *** ds1.1/lib/doc/efun/all/socket_create Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_create Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,64 ---- + socket_create - create an efun socket + + int socket_create( int mode, string | function read_callback); + + int socket_create( int mode, string | function read_callback, string | function close_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_create() creates an efun socket. mode determines which type of + socket is created. Currently supported socket modes are: + + <DL> + * MUD for sending LPC data types using TCP protocol. + * STREAM for sending raw data using TCP protocol. + * DATAGRAM for using UDP protocol. + </DL> + + The argument read_callback is the name of a function for the driver to + call when the socket gets data from its peer. The read callback should follow + this format: + + <pre> + void read_callback(int fd, mixed message) + </pre> + + Where fd is the socket which received the data, and message is the data + which was received. + + The argument close_callback is the name of a function for the driver to + call if the socket closes unexpectedly, i.e. not as the result of a + socket_close() call. The close callback should follow this format: + + <pre> + void close_callback(int fd) + </pre> + + Where fd is the socket which has closed. + NOTE: close_callback is not used with DATAGRAM mode sockets. + + socket_create() returns: + + a non-negative descriptor on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEMODENOTSUPP Socket mode not supported. + * EESOCKET Problem creating socket. + * EESETSOCKOPT Problem with setsockopt. + * EENONBLOCK Problem setting non-blocking mode. + * EENOSOCKS No more available efun sockets. + * EESECURITY Security violation attempted. + + See also: + socket_accept, + socket_bind, + socket_close, + socket_connect, + socket_listen, + socket_write + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_error ds2.1/lib/doc/efun/all/socket_error *** ds1.1/lib/doc/efun/all/socket_error Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_error Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + socket_error - return a text description of a socket error + + string socket_error( int error ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_error() returns a string describing the error signified by error. + + socket_error() returns: + + a string describing the error on success. + + "socket_error: invalid error number" on bad input. + + See also: + socket_create, + socket_connect + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_listen ds2.1/lib/doc/efun/all/socket_listen *** ds1.1/lib/doc/efun/all/socket_listen Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_listen Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,45 ---- + socket_listen - listen for connections on a socket + + int socket_listen( int s, string listen_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + To accept connections, a socket is first created with socket_create(), + the socket is them put into listening mode with socket_listen(), and + the connections are accepted with socket_accept(). The socket_listen() call + applies only to sockets of type STREAM or MUD. + + The argument listen_callback is the name of a function for the driver to + call when a connection is requested on the listening socket. The listen + callback should follow this format: + + <pre> + void listen_callback(int fd) + </pre> + + Where fd is the listening socket. + + socket_listen() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEMODENOTSUPP Socket mode not supported. + * EENOADDR Socket not bound to an address. + * EEISCONN Socket is already connected. + * EELISTEN Problem with listen. + </DL> + + See also: + socket_accept, + socket_connect, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_release ds2.1/lib/doc/efun/all/socket_release *** ds1.1/lib/doc/efun/all/socket_release Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_release Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,35 ---- + socket_release - release ownership of a socket to another object + + int socket_release( int socket, object ob, + string release_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_release() is used to change ownership (and control) of a socket + to another object. It is useful in daemon objects (like inetd) which + handle connection set-up and then transfer a connected socket to another + object for further processing. + + Socket ownership transfer involves a handshake between the current owner + object and the socket to which the current owner wishes to transfer the + socket. The handshake is initiated when socket_release() is called. + socket_release() does appropriate security/integrity checking and then + calls the release_callback function in object ob. This function is used + to notify ob that socket ownership is being transferred to it. It is + then ob's responsibility to call socket_acquire() within the release + callback function. If socket_acquire() is called then the handshake is + complete and socket ownership has been successfully transferred to ob. + ob may decline to accept responsibility for the socket by not calling + socket_acquire(), in which case ownership does not change and the + current socket owner must decide how to respond to this. + + If the socket owner is successfully transfered then socket_release() + returns EESUCCESS. If ob does not accept ownership for the socket then + EESOCKNOTRLSD is returned (both in "socket_err.h"). Other errors can be returned based on + security violation, bad socket descriptor vbalues, etc. + + See also: + socket_acquire + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/socket_write ds2.1/lib/doc/efun/all/socket_write *** ds1.1/lib/doc/efun/all/socket_write Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/socket_write Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,42 ---- + socket_write - send a message from a socket + + int socket_write( int s, mixed message, + void | string address ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_write() sends a message on a socket s. If the socket s is of type + STREAM or MUD, the socket must already be connected and the address is not + specified. If the socket is of type DATAGRAM, the address must be specified. + The address is of the form: "127.0.0.1 23". + + socket_write() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EENOADDR Socket not bound to an address. + * EEBADADDR Problem with address format. + * EENOTCONN Socket not connected. + * EEALREADY Operation already in progress. + * EETYPENOTSUPP Object type not supported. + * EEBADDATA Sending data with too many nested levels. + * EESENDTO Problem with sendto. + * EEMODENOTSUPP Socket mode not supported. + * EEWOULDBLOCK Operation would block. + * EESEND Problem with send. + * EECALLBACK Wait for callback. + </DL> + + See also: + socket_connect, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/sort_array ds2.1/lib/doc/efun/all/sort_array *** ds1.1/lib/doc/efun/all/sort_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/sort_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,29 ---- + sort_array - sort an array + + array sort_array( array arr, string fun, object ob, ... ); + + array sort_array( array arr, function f, ... ); + + array sort_array( array arr, int direction ); + + The (ob, fun) syntax behaves the same as if (: call_other, ob, fun :) + was passed as f. + + In the first two forms, the returned array is sorted with respect to + the comparison function given. The function takes two elements as + arguments, and returns -1 if if first argument is less than the second, + 0 if they are the same, or 1 if the first argument is greater than the + second. Any additional arguments are passed to the comparison function + as the third and following arguments. + + The third form returns an array with the same elements as 'arr', but + quicksorted using built-in sort routines. A 'direction' of 1 or 0 will + quicksort in ascending order, while a 'direction' of -1 will + quicksort in descending order. A limitation of the built-in + sort routines is that the array must be homogeneous, composed entirely + of a single type, where that type is string, int, or float. + Arrays of arrays are sorted by sorting based on the first element, + making database sorts possible. + + See also: + strcmp diff -c -r --new-file ds1.1/lib/doc/efun/all/sprintf ds2.1/lib/doc/efun/all/sprintf *** ds1.1/lib/doc/efun/all/sprintf Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/sprintf Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,55 ---- + sprintf - formatted output conversion + + string sprintf( string format, ... ); + + An implementation of sprintf() for LPC, with quite a few extensions + Originally implemented by Lynscar (Sean A Reith). + + This version supports the following as modifiers: + <dl> + * " " - pad positive integers with a space. + * "+" - pad positive integers with a plus sign. + * "-" - left adjusted within field size. + <b>Note:</b> sprintf() defaults to right justification, which is unnatural + in the context of a mainly string based language but has been retained for + "compatability". + * "|" - centered within field size. + * "=" - column mode if width is greater than field size. This is only + meaningful with strings, all other types ignore this. Columns are + auto-magically word wrapped. + * "#" - table mode, print a list of '\\n' separated 'words' in a + table within the field size. only meaningful with strings. + * a number - specifies the field size, a '*' specifies to use the + corresponding arg as the field size. If n is prepended with a zero, then + the field is padded zeros, otherwise it is padded with spaces (or specified pad string; see below). + * "." then a number - precision of n, simple strings truncate after this (if precision is + greater than field size, then field size = precision), tables use + precision to specify the number of columns (if precision not specified + then tables calculate a best fit), all other types ignore this. + * ":" then a number - n specifies the fs _and_ the precision, if n is prepended by a zero then the field is padded with zeros instead of spaces. + * "@" - the argument is an array. the corresponding format_info (minus the "@") is applied to each element of the array. + * "'X'" - The char(s) between the single-quotes are used to pad to + field size (defaults to space) (if both a zero (in front of field + size) and a pad string are specified, the one specified second + overrules). NOTE: to include "'" in the pad string, you must + use "\'" (as the backslash has to be escaped past the + interpreter), similarly, to include "\" requires "\\\\". + </dl> + The following are the possible type specifiers. + <dl> + * % - in which case no arguments are interpreted, and a "%" is + inserted, and all modifiers are ignored. + * O - the argument is an LPC datatype. + * s - the argument is a string. + * d, i - the integer arg is printed in decimal. + * c - the integer arg is to be printed as a character. + * o - the integer arg is printed in octal. + * x - the integer arg is printed in hex. + * X - the integer arg is printed in hex (with A-F in capitals). + * f - floating point number + </dl> + + See also: + sscanf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/sqrt ds2.1/lib/doc/efun/all/sqrt *** ds1.1/lib/doc/efun/all/sqrt Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/sqrt Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + sqrt - returns the square root of a float + + float sqrt( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + sqrt() returns the non-negative square root of its argument, `f'. The value + of `f' must not be negative. + + See also: + exp, + log, + pow + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/sscanf ds2.1/lib/doc/efun/all/sscanf *** ds1.1/lib/doc/efun/all/sscanf Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/sscanf Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,43 ---- + sscanf - match substrings in a string + + int sscanf( string str, string fmt, mixed var1, mixed var2, ... ); + + Parse a string 'str' using the format 'fmt'. The format 'fmt' + consists of text to match against 'str', separated by patterns which + begin with '%'. The following patterns are supported: + + <DL> + * '%%' - matches '%' + * '%x' - matches a hexidecimal number + * '%d' - matches a decimal number + * '%f' - matches a floating point number + * '%(regexp)' - matches anything that matches the regular + expression 'regexp' (see the regexp() efun for details) + * '%s' - matches a string; see below + </DL> + + Note that the third and following arguments are NOT expressions; they + must be valid lvalues (locations which can be assigned to). As + matches are encountered in the string, the corresponding values are + put directly into the third and following arguments. If a problem + is encountered (either some of the text between patterns doesn't + match, or a pattern can't be matched to the corresponding input) + the number of matches so far is returned, and the remaining arguments + are left unchanged. If a '*' comes immediately after the '%' in the + format, then that pattern is matched, but not assigned to a variable. + It is counted in the return value. + + '%s' is handled as follows. If it is followed by text, '%s' matches + up the the next ocurrence of the text. For example, the format + "%sxy%s" will match "fox" to the first %s when used on the string + "foxxybarxyz". If the %s occurs at the end of the string, the + remainder of the string is matched. If it is followed immediately + by another pattern, then %s matches up to the first valid match for + the following pattern. "%s%s" is illegal. + + See also: + explode, + replace_string, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/stat ds2.1/lib/doc/efun/all/stat *** ds1.1/lib/doc/efun/all/stat Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/stat Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + stat - returns information pertaining to a file or a directory + + mixed stat(string str); + mixed stat(string str, int x); + + If str is the name of a regular file (not a directory), then stat() + will return an array of information pertaining to that file. The + form of the array is as follows: + + ({ file_size, last_time_file_touched, time_object_loaded }) + + If stat is called on a directory (not a regular file), or with a second + argument of -1, then stat() behaves identically to get_dir(). + + See also: + get_dir, + stat diff -c -r --new-file ds1.1/lib/doc/efun/all/store_variable ds2.1/lib/doc/efun/all/store_variable *** ds1.1/lib/doc/efun/all/store_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/store_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + store_variable - set the value of a variable + + void store_variable(string, mixed); + + Set the value of the variable specified by the first argument to the value + specfied by the second argument. Note that the variable must be defined, and + must be defined in this_object(). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + restore_variable, + fetch_variable, + save_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/strcmp ds2.1/lib/doc/efun/all/strcmp *** ds1.1/lib/doc/efun/all/strcmp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/strcmp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + strcmp - determines the lexical relationship between two strings + + int strcmp( string one, string two ); + + This implementatin of strcmp() is identical to the one found in C libraries. + If string one lexically precedes string two, then strcmp() returns a number + less than 0. If the two strings have the same value, strcmp() returns 0. + If string two lexically precedes string one, then strcmp() returns a number + greater than 0. This efunction is particularly useful in the compare + functions needed by sort_array(). + + Note that relational operators (<, >, etc) can also be used to compare + strings. + + See also: + sort_array + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/stringp ds2.1/lib/doc/efun/all/stringp *** ds1.1/lib/doc/efun/all/stringp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/stringp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + stringp - determine whether or not a given variable is a string + + int stringp( mixed arg ); + + Returns 1 if 'arg' is a string, and zero if not. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/strlen ds2.1/lib/doc/efun/all/strlen *** ds1.1/lib/doc/efun/all/strlen Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/strlen Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + strlen - returns the length of a string + + int strlen( string str ); + + strlen() returns the number of characters in the string 'str'. + + See also: + sizeof + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/strsrch ds2.1/lib/doc/efun/all/strsrch *** ds1.1/lib/doc/efun/all/strsrch Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/strsrch Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + strsrch - search for substrings in a string + + int strsrch( string str, string substr | int char, int flag ); + + strsrch() searches for the first occurance of the string 'substr' in the + string 'str'. The last occurance of 'substr' can be found by passing '-1' + as the 3rd argument (which is optional). If the second argument is an + integer, that character is found (like C's strchr()/strrchr().) The empty + string or null value cannot be searched for. + + The integer offset of the first (last) match is returned. -1 is returned + if there was no match, or an error occurred (bad args, etc). + + See also: + sscanf, + replace_string, + regexp + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/swap ds2.1/lib/doc/efun/all/swap *** ds1.1/lib/doc/efun/all/swap Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/swap Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + swap - swap out a file explicitly + + void swap( object ); + + This efun is only available if the driver is compiled with -DDEBUG. + + This efun should be reserved for debugging only. It + allows an object to be explicitly swapped out. If + enabled, it is strongly recommended that a simul_efun + override (for this efun) be used to prevent abuse. + + Note: objects which have been destructed, already + swapped out, contain a heart beat, cloned, inherited, + or interactive, cannot be swapped out. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/tail ds2.1/lib/doc/efun/all/tail *** ds1.1/lib/doc/efun/all/tail Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/tail Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + tail - displays the latter portion of a file + + int tail( string path ); + + This efunction displays the latter portion of the file named by path. + It returns 1 if successful, 0 otherwise (e.g. when the file is protected + against reading). + + See also: + read_file, + read_buffer, + file_size diff -c -r --new-file ds1.1/lib/doc/efun/all/tan ds2.1/lib/doc/efun/all/tan *** ds1.1/lib/doc/efun/all/tan Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/tan Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + tan - return the tangent of a float + + float tan( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the tangent of its argument, 'f', measured in radians. + + See also: + acos, + asin, + atan, + cos, + sin diff -c -r --new-file ds1.1/lib/doc/efun/all/tell_object ds2.1/lib/doc/efun/all/tell_object *** ds1.1/lib/doc/efun/all/tell_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/tell_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + tell_object - send a message to an object + + void tell_object( object ob, string str ); + + Send a message 'str' to object 'ob'. If it is an interactive object (a player), + then the message will go to him, otherwise it will go to the local + function "catch_tell()". + + See also: + write, + shout, + say, + tell_room, + catch_tell + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/tell_room ds2.1/lib/doc/efun/all/tell_room *** ds1.1/lib/doc/efun/all/tell_room Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/tell_room Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + tell_room - send a message to all objects in a room + + void tell_room( mixed ob, string str, object array exclude ); + + Send a message 'str' to object all objects in the room 'ob'. 'ob' can also + be the filename of the room (string). If 'exclude' is specified, all + objects in the exclude array will not receive the message. + + See also: + write, + shout, + say, + tell_object, + catch_tell + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/terminal_colour ds2.1/lib/doc/efun/all/terminal_colour *** ds1.1/lib/doc/efun/all/terminal_colour Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/terminal_colour Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + terminal_colour - replaces codes in a string + + string terminal_colour(string str, mapping m, int wrap, int indent); + + terminal_colour() replaces each occurrence of %^key%^ in str with 'value', + where 'key' and 'value' are the elements in the mapping m. + + 'wrap' is the optional column number to wrap at, and 'indent' is the + amount to indent the second and following lines. Codes are assumed to + change the mode of the terminal and not generate any printable + characters for the purposes of wrapping. + + This efun is only available if PACKAGE_CONTRIB is defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/test_bit ds2.1/lib/doc/efun/all/test_bit *** ds1.1/lib/doc/efun/all/test_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/test_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + test_bit - test a bit in a bitstring + + int test_bit( string str, int n ); + + Returns 1 if bit 'n' was set in string 'str', and zero otherwise. + + See also: + set_bit, + clear_bit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/this_interactive ds2.1/lib/doc/efun/all/this_interactive *** ds1.1/lib/doc/efun/all/this_interactive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/this_interactive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + this_interactive - return the object representing the current player + + object this_interactive(); + + Return the object representing the player that caused the calling function + to be called. This returns what this_player() was originally even if + it changed later due to enable_commands() or command() + + See also: + this_player + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/this_object ds2.1/lib/doc/efun/all/this_object *** ds1.1/lib/doc/efun/all/this_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/this_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + this_object - return the object pointer of the calling object + + object this_object(); + + Return the object pointer of the current object. Useful for passing the + current object to other functions. + + See also: + this_player, + previous_object, + origin + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/this_player ds2.1/lib/doc/efun/all/this_player *** ds1.1/lib/doc/efun/all/this_player Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/this_player Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + this_player - return the object representing the current player + + object this_player( int flag ); + + this_player() is exactly the same as this_user(). + + See also: + this_user diff -c -r --new-file ds1.1/lib/doc/efun/all/this_user ds2.1/lib/doc/efun/all/this_user *** ds1.1/lib/doc/efun/all/this_user Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/this_user Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + this_user - return the object representing the current interactive + + Return the object representing the user that caused the calling function + to be called. Note that this_user() may return a different value than + this_object() even when called from within a user object. If this_user + is called as this_user(1) then the returned value will be the interactive + that caused the calling function to be called. this_user(1) may return + a different value than this_user() in certain cases (such as when command() + is used by an admin to force a user to perform some command). + + See also: + this_object diff -c -r --new-file ds1.1/lib/doc/efun/all/throw ds2.1/lib/doc/efun/all/throw *** ds1.1/lib/doc/efun/all/throw Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/throw Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + throw - forces an error to occur in an object. + + void throw(mixed); + + Throw can be used to send an arbitrary value to an enclosing catch() statement. + If you want to raise a general error message, see error(), as that will + behave better if it is not caught. Control is transfered directly to the + enclosing catch() statement, and the value of the catch() statement is the + value thrown. + + See also: + catch, + error + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/time ds2.1/lib/doc/efun/all/time *** ds1.1/lib/doc/efun/all/time Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/time Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + debug_message - send a message to the driver's stdout + + void debug_message(string); + + The string argument is printed on the driver's stdout, as well as being added + to the debug.log file. + + See also: + ctime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/time_expression ds2.1/lib/doc/efun/all/time_expression *** ds1.1/lib/doc/efun/all/time_expression Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/time_expression Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + time_expression - return the amount of real time that an expression took + + int time_expression( mixed expr ); + + int time_expression { ... } + + Evaluate <expr> or the specified block of code. The amount of real time + that passes during the evaluation of <expr>, in microseconds, is returned. + The precision of the value is + not necessarily 1 microsecond; in fact, it probably is much less precise. + + See also: + rusage, + function_profile, + time + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/to_float ds2.1/lib/doc/efun/all/to_float *** ds1.1/lib/doc/efun/all/to_float Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/to_float Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + to_float - convert an int to a float + + float to_float( int i ); + + The to_float() call returns the number of type 'float' that is equivalent to + the int 'i'. + + See also: + to_int, + read_buffer, + sprintf, + sscanf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/to_int ds2.1/lib/doc/efun/all/to_int *** ds1.1/lib/doc/efun/all/to_int Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/to_int Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + to_int - convert a float or buffer to an int + + int to_int( float x ); + int to_int( buffer x ); + int to_int( string x ); + + If 'x' is a float, the to_int() call returns the number of type 'int' that is + equivalent to 'x' (with any decimal stripped off). If 'x' is a buffer, the + call returns the integer (in network-byte-order) that is embedded in the + buffer. If 'x' is a string, then the string is converted to an integer. + An undefined value is returned if the string is not a valid number. + + See also: + to_float, + read_buffer diff -c -r --new-file ds1.1/lib/doc/efun/all/trace ds2.1/lib/doc/efun/all/trace *** ds1.1/lib/doc/efun/all/trace Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/trace Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,25 ---- + trace - sets trace flags and returns the old ones + + int trace( int traceflags ); + + This efun is only available if TRACE and PACKAGE_DEVELOP are compiled in. + + Sets the trace flags and returns the old trace flags. + When tracing is on a lot of information is printed during execution. + + The trace bits are: + <DL> + * 1 - Trace all function calls to lfuns. + * 2 - Trace all calls to "call_other". + * 4 - Trace all function returns. + * 8 - Print arguments at function calls and return values. + * 16 - Print all executed stack machine instructions (produces a lot of output!). + * 32 - Enable trace in heart beat functions. + * 64 - Trace calls to apply. + * 128 - Show object name in tracing. + </DL> + + See also: + traceprefix + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/traceprefix ds2.1/lib/doc/efun/all/traceprefix *** ds1.1/lib/doc/efun/all/traceprefix Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/traceprefix Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + traceprefix - sets the prefix determining which objects to trace + + string traceprefix( string prefix ); + + This efun is only available if TRACE and PACKAGE_DEVELOP are compiled in. + + If the the traceprefix is set (i.e. not 0) tracing will only occur in objects + having a name with the set prefix. + + The old value is returned. + + See also: + trace + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/all/typeof ds2.1/lib/doc/efun/all/typeof *** ds1.1/lib/doc/efun/all/typeof Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/typeof Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + typeof - return the type of an expression + + int typeof( mixed var ); + + Return the type of an expression. The return values are given in + the driver include "type.h". They are: + + <pre> + INT "int" + STRING "string" + ARRAY "array" + OBJECT "object" + MAPPING "mapping" + FUNCTION "function" + FLOAT "float" + BUFFER "buffer" + CLASS "class" + </pre> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/undefinedp ds2.1/lib/doc/efun/all/undefinedp *** ds1.1/lib/doc/efun/all/undefinedp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/undefinedp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + undefinedp - determine whether or not a given value is undefined. + + int undefinedp( mixed arg ); + + Return 1 if `arg' is undefined. 'arg' will be undefined in the following + cases: + + <DL> + * it is a variable set equal to the return value of a call_other to a + non-existent method (e.g. arg = call_other(obj, "???")). + * it is a variable set equal to the return value of an access of an + element in a mapping that doesn't exist (e.g. arg = map[not_there]). + * it has not yet been initialized. + * it points to a destructed object. + * it is a function (formal) parameter that corresponds to a missing actual argument. + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/unique_array ds2.1/lib/doc/efun/all/unique_array *** ds1.1/lib/doc/efun/all/unique_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/unique_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,33 ---- + unique_array - partitions an array of objects into groups + + array unique_array(object array obarr, string separator); + + array unique_array(object array obarr, string separator, mixed skip); + + array unique_array(array arr, function f); + + array unique_array(array arr, function f, mixed skip); + + Groups objects/values together for which the `separator' function + returns the same value. In the first case, "separator" is a string function + name to try on each object. In the second case, the function f is called + with the element as the argument. If 'skip' is passed, elements for which + the separator function returns the same as 'skip' are omitted from the + return value. + + The return value is an array of arrays of the form: + <pre> + ({ + ({Same1:1, Same1:2, Same1:3, .... Same1:N }), + ({Same2:1, Same2:2, Same2:3, .... Same2:N }), + ({Same3:1, Same3:2, Same3:3, .... Same3:N }), + .... + .... + ({SameM:1, SameM:2, SameM:3, .... SameM:N }), + }) + </pre> + + i.e. an array of arrays, where each of the elements in the sub arrays returned + the same value as the other elements in the same sub array. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/unique_mapping ds2.1/lib/doc/efun/all/unique_mapping *** ds1.1/lib/doc/efun/all/unique_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/unique_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + unique_mapping - partition an array into groups + + mapping unique_mapping(array arr, string fun, object ob, ...); + + mapping unique_mapping(array arr, function f, ...); + + unique_mapping() evaluates the function 'f' with each element of the + array 'arr', and constructs a mapping with the return values as keys, + and subarrays of elements that returned value value as values. + + See also: + unique_array + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/upper_case ds2.1/lib/doc/efun/all/upper_case *** ds1.1/lib/doc/efun/all/upper_case Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/upper_case Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + upper_case - return the uppercase version of a given string + + string upper_case(string); + + Return the uppercase version of a given string (original string remains + unchanged). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + capitalize, + lower_case + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/uptime ds2.1/lib/doc/efun/all/uptime *** ds1.1/lib/doc/efun/all/uptime Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/uptime Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + uptime - return the number of seconds elapsed since the last driver reboot + + int uptime(); + + This function returns the number of seconds since the last driver reboot. + + See also: + time, + ctime, + localtime, + time_expression + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/userp ds2.1/lib/doc/efun/all/userp *** ds1.1/lib/doc/efun/all/userp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/userp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + userp - determine if a given object was once interactive + + int userp( object ); + + Returns 1 if the arg was once interactive. + + See also: + interactive, + users, + living + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/users ds2.1/lib/doc/efun/all/users *** ds1.1/lib/doc/efun/all/users Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/users Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + users - return an array of objects containing all interactive players + + object array users(); + + Return an array of objects, containing all interactive players. + + See also: + livings, + children, + objects + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/values ds2.1/lib/doc/efun/all/values *** ds1.1/lib/doc/efun/all/values Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/values Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + values - return an array of the values from the (key, value) pairs in a mapping + + array values( mapping m ); + + values() returns an array of values corresponding to the value elements + in the (key, value) pairs stored in the mapping m. + + For example, if: + + <pre> + mapping m; + + m = (["hp" : 35, "sp" : 42, "mass" : 100]); + </pre> + + then + + <pre> + values(m) == ({35, 42, 100}) + </pre> + + Note: the values will be returned in the same order as the corresponding + keys. + + See also: + keys diff -c -r --new-file ds1.1/lib/doc/efun/all/variables ds2.1/lib/doc/efun/all/variables *** ds1.1/lib/doc/efun/all/variables Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/variables Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + variables - list all the variables in a given object. + + string array variables(object, int default: 0); + + variables() can return two different things. If the second argument is + 0 (which it is by default) it will return an array containing the names + of all the variables in the object passed as the first argument. If the + second argument is non-zero, more information about each variable is + given. For a non-zero second argument, each array element contains + the following: + + ({ variable_name, variable_type }). + + Where variable_name is the name of the given variable, and variable_type + is the type of the variable, such as "string" or "private int" etc. + + This efun is only available if PACKAGE_CONTRIB is defined in the + options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/virtualp ds2.1/lib/doc/efun/all/virtualp *** ds1.1/lib/doc/efun/all/virtualp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/virtualp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + virtualp - determine whether or not a given variable points to a virtual object + + int virtualp( object arg ); + + Returns true (1) if the argument is objectp() and the O_VIRTUAL flag is set. + The driver sets the O_VIRTUAL flag for those objects created via the + 'compile_object' function in the master object. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/wizardp ds2.1/lib/doc/efun/all/wizardp *** ds1.1/lib/doc/efun/all/wizardp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/wizardp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + wizardp - determines if a given object had enable_wizard() performed in it + + int wizardp( object ); + + This efun is only available if NO_WIZARDS is not compiled in. + + Returns 1 if the arg had enable_wizard() performed on it. + + See also: + disable_wizard, + enable_wizard + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/write ds2.1/lib/doc/efun/all/write *** ds1.1/lib/doc/efun/all/write Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/write Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + write() - send a message to current player + + void write( mixed str ); + + Write a message `str' to current player. `str' can also be a number, which + will be translated to a string. + + See also: + message, + tell_object, + tell_room, + shout, + say + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/write_buffer ds2.1/lib/doc/efun/all/write_buffer *** ds1.1/lib/doc/efun/all/write_buffer Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/write_buffer Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + write_buffer - write a buffer to a file + + int write_buffer(mixed dest, int start, mixed source ); + + If `dest' is a file, then `source' must be an int (and will be written to + the file in network-byte-order), a buffer, or a string, and `source' will + be written to the file `dest' starting at byte # `start'. + + If `dest' is a buffer, then `source' will be written into the buffer starting + at byte # `start' in the buffer. If `source' is an int, it will be written + in network-byte-order. + + See also: + read_buffer, + allocate_buffer + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/all/write_bytes ds2.1/lib/doc/efun/all/write_bytes *** ds1.1/lib/doc/efun/all/write_bytes Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/write_bytes Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + write_bytes - writes a contiguous series of bytes to a file + + int write_bytes( string path, int start, string series ); + + This function writes the bytes in 'series' into the file named by 'path' + beginning at byte # 'start'. It returns zero (0) upon failure, 1 otherwise. + + See also: + write_file, + read_bytes diff -c -r --new-file ds1.1/lib/doc/efun/all/write_file ds2.1/lib/doc/efun/all/write_file *** ds1.1/lib/doc/efun/all/write_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/all/write_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + write_file - appends a string to a file + + int write_file( string file, string str, int flag ); + + Append the string `str' into the file `file'. Returns 0 or 1 for + failure or success. If flag is 1, write_file overwrites instead of + appending. + + See also: + read_file, + write_buffer, + file_size diff -c -r --new-file ds1.1/lib/doc/efun/arrays/allocate ds2.1/lib/doc/efun/arrays/allocate *** ds1.1/lib/doc/efun/arrays/allocate Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/arrays/allocate Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + allocate - allocate an array + + array allocate( int size ); + + Allocate an array of <size> elements. The number of elements must be >= 0 + and not bigger than a system maximum (usually ~10000). All elements are + initialized to 0. + + See also: + sizeof, + allocate_mapping + diff -c -r --new-file ds1.1/lib/doc/efun/arrays/filter_array ds2.1/lib/doc/efun/arrays/filter_array *** ds1.1/lib/doc/efun/arrays/filter_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/arrays/filter_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + filter_array - return a selective sub-array + + array filter_array( array arr, string fun, object ob, mixed extra, ... ); + + array filter_array( array arr, function f, mixed extra, ...); + + filter_array() is really the same as the filter() efun. + + See also: + filter + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/arrays/index ds2.1/lib/doc/efun/arrays/index *** ds1.1/lib/doc/efun/arrays/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/arrays/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + Array efuns + + These efuns exist for the manipulation of array values: + + <DL> + * allocate + * arrayp + * filter_array + * map_array + * member_array + * pointerp + * sort_array + * unique_array + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/arrays/map_array ds2.1/lib/doc/efun/arrays/map_array *** ds1.1/lib/doc/efun/arrays/map_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/arrays/map_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + map_array - modify an array of elements via application of a function + + array map_array( array arr, string fun, object ob, mixed extra, ... ); + + array map_array( array arr, function f, mixed extra, ... );; + + The map_array() efun is really just an alias for the map() efun. + + See also: + map diff -c -r --new-file ds1.1/lib/doc/efun/arrays/member_array ds2.1/lib/doc/efun/arrays/member_array *** ds1.1/lib/doc/efun/arrays/member_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/arrays/member_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + member_array - returns index of an occurence of a given item in an array or string + + int member_array( mixed item, mixed arr); + + int member_array( mixed item, mixed arr, int start); + + Returns the index of the first occurence of `item' in the array or string + `arr', or the first occurence at or after 'start'. + If the item is not found, then -1 is returned. + + For the purpose of this efun, strings are considered to be arrays of ints. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/arrays/sort_array ds2.1/lib/doc/efun/arrays/sort_array *** ds1.1/lib/doc/efun/arrays/sort_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/arrays/sort_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,29 ---- + sort_array - sort an array + + array sort_array( array arr, string fun, object ob, ... ); + + array sort_array( array arr, function f, ... ); + + array sort_array( array arr, int direction ); + + The (ob, fun) syntax behaves the same as if (: call_other, ob, fun :) + was passed as f. + + In the first two forms, the returned array is sorted with respect to + the comparison function given. The function takes two elements as + arguments, and returns -1 if if first argument is less than the second, + 0 if they are the same, or 1 if the first argument is greater than the + second. Any additional arguments are passed to the comparison function + as the third and following arguments. + + The third form returns an array with the same elements as 'arr', but + quicksorted using built-in sort routines. A 'direction' of 1 or 0 will + quicksort in ascending order, while a 'direction' of -1 will + quicksort in descending order. A limitation of the built-in + sort routines is that the array must be homogeneous, composed entirely + of a single type, where that type is string, int, or float. + Arrays of arrays are sorted by sorting based on the first element, + making database sorts possible. + + See also: + strcmp diff -c -r --new-file ds1.1/lib/doc/efun/arrays/unique_array ds2.1/lib/doc/efun/arrays/unique_array *** ds1.1/lib/doc/efun/arrays/unique_array Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/arrays/unique_array Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,33 ---- + unique_array - partitions an array of objects into groups + + array unique_array(object array obarr, string separator); + + array unique_array(object array obarr, string separator, mixed skip); + + array unique_array(array arr, function f); + + array unique_array(array arr, function f, mixed skip); + + Groups objects/values together for which the `separator' function + returns the same value. In the first case, "separator" is a string function + name to try on each object. In the second case, the function f is called + with the element as the argument. If 'skip' is passed, elements for which + the separator function returns the same as 'skip' are omitted from the + return value. + + The return value is an array of arrays of the form: + <pre> + ({ + ({Same1:1, Same1:2, Same1:3, .... Same1:N }), + ({Same2:1, Same2:2, Same2:3, .... Same2:N }), + ({Same3:1, Same3:2, Same3:3, .... Same3:N }), + .... + .... + ({SameM:1, SameM:2, SameM:3, .... SameM:N }), + }) + </pre> + + i.e. an array of arrays, where each of the elements in the sub arrays returned + the same value as the other elements in the same sub array. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/buffers/allocate_buffer ds2.1/lib/doc/efun/buffers/allocate_buffer *** ds1.1/lib/doc/efun/buffers/allocate_buffer Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/buffers/allocate_buffer Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + allocate_buffer - allocate a buffer + + buffer allocate_buffer( int size ); + + This efun is only available if DISALLOW_BUFFER_TYPE is not compiled in. + + Allocate a buffer of 'size' elements. The number of elements must be >= 0 + and not bigger than a system maximum (usually ~10000). All elements are + initialized to 0. + + See also: + bufferp, + read_buffer, + write_buffer + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/buffers/crc32 ds2.1/lib/doc/efun/buffers/crc32 *** ds1.1/lib/doc/efun/buffers/crc32 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/buffers/crc32 Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + crc32 - compute the cycle redundancy code for a buffer or string + + int crc32( buffer | string x ); + + Computes and returns the CRC-32 code for the given buffer or string, `x'. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/buffers/index ds2.1/lib/doc/efun/buffers/index *** ds1.1/lib/doc/efun/buffers/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/buffers/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + Buffer Efuns + + The following efuns are available for manipulating buffer values: + + <DL> + * allocate_buffer + * bufferp + * crc32 + * read_buffer + * write_buffer + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/buffers/read_buffer ds2.1/lib/doc/efun/buffers/read_buffer *** ds1.1/lib/doc/efun/buffers/read_buffer Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/buffers/read_buffer Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + read_buffer - read from a file and return a buffer + + mixed read_buffer( mixed src, int start, int len); + + This efun is only available if DISALLOW_BUFFER_TYPE is not compiled in. + + If 'src' is a string (filename), then the filename will be read, starting + at byte # 'start', for 'len' bytes, and returned as a buffer. If neither + argument is given, the entire file is read. + + If 'src' is a buffer, then characters are read from the buffer beginning + at byte # 'start' in the buffer, and for 'len' # of bytes, and returned + as a string. + + Note that the maximum number of bytes you can read from a file and into + a buffer is controlled via the 'maximum byte transfer' parameter in the + runtime config file. + + See also: + write_buffer, + allocate_buffer, + bufferp, + read_bytes, + write_bytes + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/buffers/write_buffer ds2.1/lib/doc/efun/buffers/write_buffer *** ds1.1/lib/doc/efun/buffers/write_buffer Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/buffers/write_buffer Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + write_buffer - write a buffer to a file + + int write_buffer(mixed dest, int start, mixed source ); + + If `dest' is a file, then `source' must be an int (and will be written to + the file in network-byte-order), a buffer, or a string, and `source' will + be written to the file `dest' starting at byte # `start'. + + If `dest' is a buffer, then `source' will be written into the buffer starting + at byte # `start' in the buffer. If `source' is an int, it will be written + in network-byte-order. + + See also: + read_buffer, + allocate_buffer + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/call_other ds2.1/lib/doc/efun/calls/call_other *** ds1.1/lib/doc/efun/calls/call_other Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/call_other Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,55 ---- + call_other - call a function in another object + + mixed call_other(mixed ob, string func, ...); + + mixed call_other(mixed ob, array args); + + mixed call_other(array obs, string func, ...); + + mixed call_other(array obs, array args); + + ob is either an object pointer, or a string filename (suitable for + find_object()). obs is an array of object pointers and strings. + Using an array as the first argument does a call_other for each element of + the array, and returns an array of the results. + If the array form is used for args, then the first element is the function + name, and the remainder are the arguments; e.g.: + + call_other(ob, ({ "foo", 1, 3, 5 })) + + and + + call_other(ob, "foo", 1, 3, 5) + + are equivalent. The function foo() is called in the object ob with the + arguments (1, 3, 5). The return value of call_other() is the value + returned from the foo() function. In the case of an array of objects, + the return value of call_other() is an array of the return values. + + There is a much more attractive way to do call_others; + call_other(x, "y", z, ...) is the same as: + + x->y(z, ...) + + ie, + + call_other(ob, "query_name"); + + could be written as: + + ob->query_name(); + + Writing out the call_other call is mainly used when the function name + is in a variable, i.e: + + <pre> + void do_test(string fname, int x) { + call_other(fname, "test_" + x); + } + </pre> + + An example of using an array as the first argument: + + users()->quit(); + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/call_out ds2.1/lib/doc/efun/calls/call_out *** ds1.1/lib/doc/efun/calls/call_out Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/call_out Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + call_out - delayed function call in same object + + int call_out( function fun, int delay, mixed arg, ... ); + + Set up a call to 'fun'. If fun is a string, it is interpreted as the + name of a function in this_object(). The call will take place 'delay' + seconds later, with the arguments 'arg' and following provided. + + Note: + Unless THIS_PLAYER_IN_CALL_OUT is defined, you can't rely on + write() or say() in 'fun' since this_player() is set to 0. + Use tell_object() instead. + + If THIS_PLAYER_IN_CALL_OUT is defined, this_player() is the same as + it was when the call_out() call was scheduled. + + The return value will be a unique integer identifying the call_out, if + CALLOUT_HANDLES is defined. This 'handle' can be passed to + remove_call_out() and find_call_out(). + + See also: + remove_call_out, + call_out_info, + find_call_out + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/call_stack ds2.1/lib/doc/efun/calls/call_stack *** ds1.1/lib/doc/efun/calls/call_stack Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/call_stack Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + call_stack - returns information about the functions involved in calling this function + + array call_stack(int); + + If the int argument is 0, call_stack() returns an array of the names of the + on the call stack, with the first one being the most recent (i.e. the + currently running program). If the int argument is 1, call_stack returns + the objects in which that program is executing. If it is 2, the name + of the functions are returned. If it is 3, the value of origin() in that + frame is returned. + + See also: + previous_object, + origin diff -c -r --new-file ds1.1/lib/doc/efun/calls/catch ds2.1/lib/doc/efun/calls/catch *** ds1.1/lib/doc/efun/calls/catch Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/catch Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + catch - catch an evaluation error + + mixed catch( mixed expr ); + + mixed catch { ... }; + + Note: catch is really a keyword and not an efun. + + The code inside the { ... } or the expression is evaluated. If there + is no error, catch() returns zero. If there is an error, a string (with + a leading '*') will be returned. + + The function throw() can also be used to immediately return any value, + except 0. + + The catch() is somewhat costly, and should not be used just anywhere. + Rather, use it at places where an error would destroy consistency. + + See also: + error, + throw, + error_handler + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/index ds2.1/lib/doc/efun/calls/index *** ds1.1/lib/doc/efun/calls/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + Call Efuns + + The following efuns deal with making, redirecting, and intercepting various + calls between objects. + + <DL> + * call_other + * call_out + * call_stack + * catch + * origin + * previous_object + * query_shadowing + * remove_call_out + * shadow + * this_object + * throw + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/calls/origin ds2.1/lib/doc/efun/calls/origin *** ds1.1/lib/doc/efun/calls/origin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/origin Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + origin - determine how the current function was called + + string origin(); + + Returns an string specifying how the current function was called. These + values can be found in the driver include "origin.h". Current values are: + + <DL> + * "driver" - from the driver: applies, heart_beats, etc + * "local" - local function call + * "call_other" - call_other + * "simul" - use of a simul_efun + * "call_out" - via a call_out + * "efun" - from an efun that takes a function pointer (sort_array, etc) + </DL> + + See also: + previous_object diff -c -r --new-file ds1.1/lib/doc/efun/calls/previous_object ds2.1/lib/doc/efun/calls/previous_object *** ds1.1/lib/doc/efun/calls/previous_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/previous_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + previous_object - returns the object(s) that called the current function + + object previous_object(); + mixed previous_object(int x); + + Returns an object pointer to the object, if any, that called current function. + Note that local function calls do not set previous_object() to the current + object, but leave it unchanged. If passed a positive integer, it goes back + the given number of previous objects in the calling chain. + previous_object(0) is the same as previous_object(), previous_object(1) is + the previous object's previous_object(), etc. previous_object(-1) returns + an array containing all of the previous objects. + + See also: + call_other, + call_out, + origin + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/query_shadowing ds2.1/lib/doc/efun/calls/query_shadowing *** ds1.1/lib/doc/efun/calls/query_shadowing Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/query_shadowing Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + query_shadowing - determine whether or not a given object it shadowing another + + object query_shadowing( object ob ); + + This efun is only available if NO_SHADOWS is not compiled in. + + Returns the object that `ob' is shadowing, or zero (0) if it is not + shadowing any object. + + See also: + shadow, + valid_shadow + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/remove_call_out ds2.1/lib/doc/efun/calls/remove_call_out *** ds1.1/lib/doc/efun/calls/remove_call_out Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/remove_call_out Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + remove_call_out - remove a pending call_out + + int remove_call_out( string fun | int handle ); + + Remove next pending call out for function `fun' in the current object, + or the call_out() which returned the integer 'handle'. + The return value is the time remaining before the callback is to be called. + The returned value is -1 if there were no call out pending to this function. + If fun is zero, all the call_outs of the object are removed. + + See also: + call_out, + call_out_info + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/remove_shadow ds2.1/lib/doc/efun/calls/remove_shadow *** ds1.1/lib/doc/efun/calls/remove_shadow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/remove_shadow Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + remove_shadow - clear all the shadows related to an object. + + int remove_shadow(object); + + This function removes ALL shadows associated with the object passed + as the argument. Note this means all shadows ON the object, and all shadows + ORIGINATED by the object. + + This function requires PACKAGE_CONTRIB to be defined in the options file. + This function also requires that the option NO_SHADOWS be undefined. + + See also: + shadow + diff -c -r --new-file ds1.1/lib/doc/efun/calls/shadow ds2.1/lib/doc/efun/calls/shadow *** ds1.1/lib/doc/efun/calls/shadow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/shadow Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,41 ---- + shadow - shadow one or more functions in some object + + object shadow( object ob, int flag ); + + This efun is only available if NO_SHADOWS is not compiled in. + + If 'flag' is 1 or missing, then current object will shadow 'ob'. If + 'flag' is 0, then either 0 will be returned, or the object that is + already shadowing 'ob'. + + The master object defines the function "valid_shadow()". If it returns 1 + the target object can't be shadowed, and the "shadow()" function will + return 0 instead of 'ob'. + + If an object 'a' shadows an object 'b', then all "call_other(func)" to 'b' + will be redirected to 'a'. If object 'a' has not defined the function, + then the call will be forwarded to 'b' (as if there were no shadow). + There is only one object that can call functions in 'b' with + call_other(), and that is 'a'. Not even object 'b' can "call_other()" + itself. All normal (internal) function calls inside 'b' will however remain + internal to 'b'. + + There are two ways to remove the shadow. Either destruct it, or the object + that was shadowed. In the latter case, the shadow will also be destructed + automatically. Also, there is a efun remove_shadow() in the contrib package. + + The result is that it is possible to hide an object behind another one, + but everything can be totally transparent. The shadow() efunction makes + it possible to change the behavior of an object without changing the + code for the object in question. One possible use for shadow() is to + add special capabilities to various classes of players (thief, fighter, + mage, etc). This usage would make it possible to keep the player object + much simpler than it could be if the code for the various classes had + to be in the player object itself. + + See also: + destruct, + query_shadowing, + valid_shadow + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/this_object ds2.1/lib/doc/efun/calls/this_object *** ds1.1/lib/doc/efun/calls/this_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/this_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + this_object - return the object pointer of the calling object + + object this_object(); + + Return the object pointer of the current object. Useful for passing the + current object to other functions. + + See also: + this_player, + previous_object, + origin + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/calls/throw ds2.1/lib/doc/efun/calls/throw *** ds1.1/lib/doc/efun/calls/throw Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/calls/throw Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + throw - forces an error to occur in an object. + + void throw(mixed); + + Throw can be used to send an arbitrary value to an enclosing catch() statement. + If you want to raise a general error message, see error(), as that will + behave better if it is not caught. Control is transfered directly to the + enclosing catch() statement, and the value of the catch() statement is the + value thrown. + + See also: + catch, + error + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/compile/generate_source ds2.1/lib/doc/efun/compile/generate_source *** ds1.1/lib/doc/efun/compile/generate_source Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/compile/generate_source Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + generate_source - generates the C code corresponding to a give object(s) + + int generate_source(string file); + + int generate_source(string array files); + + This efun is only available if LPC_TO_C is compiled into the driver. + + generate_source() calls the LPC->C compiler to generate the source code + for a given object or objects. If more than one file is passed, a directory + named 'mudlib' is created in the SAVE_BINARIES directory, and that directory + can be copied into the driver source directory and compiled into the driver. + + If one file is given, the C source for that file is compiled, and the driver + attempts to link it into the running executable using the RUNTIME_LOADING + option. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/compile/index ds2.1/lib/doc/efun/compile/index *** ds1.1/lib/doc/efun/compile/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/compile/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + Compilation efuns + + The only efun in here currently is the LPC->C one. + + <DL> + * generate_source + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/cp ds2.1/lib/doc/efun/filesystem/cp *** ds1.1/lib/doc/efun/filesystem/cp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/cp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + cp - copy a file + + int cp(string src, string dst); + + Copies the file 'src' to the file 'dst'. + + Returns 1 for success, returns -1 if the first src is unreadable, -2 if + dst is unreadable, and -3 if an i/o error occurs. + + See also: + rm, + rmdir, + rename, + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/file_length ds2.1/lib/doc/efun/filesystem/file_length *** ds1.1/lib/doc/efun/filesystem/file_length Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/file_length Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + file_length - get the number of lines in a file + + int file_length( string file ); + + file_length() returns the number of lines in file 'file'. Size -1 + indicates that 'file' either does not exist, or that it is not + readable. Size -2 indicates that 'file' is a directory. + + Note that this efun is not particularly fast on long files, since + determining the number of lines requires reading the entire file. + + See also: + file_size, + stat, + get_dir diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/file_size ds2.1/lib/doc/efun/filesystem/file_size *** ds1.1/lib/doc/efun/filesystem/file_size Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/file_size Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + file_size - get the size of a file + + int file_size( string file ); + + file_size() returns the size of file 'file' in bytes. Size -1 + indicates that 'file' either does not exist, or that it is not + readable. Size -2 indicates that 'file' is a directory. + + See also: + file_length, + stat, + get_dir diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/get_dir ds2.1/lib/doc/efun/filesystem/get_dir *** ds1.1/lib/doc/efun/filesystem/get_dir Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/get_dir Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + get_dir - returns information pertaining to a filesystem directory + + mixed array get_dir(string dir); + + mixed array get_dir(string dir, int flag); + + If `dir' is a filename ('*' and '?' wildcards are supported), an array of + strings is returned containing all filenames that match the specification. + If `dir' is a directory name (ending with a slash--ie: "/u/", "/adm/", etc), + all filenames in that directory are returned. + + If called with a second argument equal to -1, get_dir will return an array + of subarrays, where the format of each subarray is: + + ({ filename, size_of_file, last_time_file_touched }) + + Where filename is a string and last_time_file_touched is an integer being + number of seconds since January 1, 1970 (same format as time()). The + size_of_file element is the same value that is returned by file_size(); the + size of the file in bytes, or -2 if it's a directory. + + See also: + file_size, + stat, + time, + ctime diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/index ds2.1/lib/doc/efun/filesystem/index *** ds1.1/lib/doc/efun/filesystem/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + Filesystem Efuns + + These are the efuns which are available for manipulating files. + + <DL> + * cp + * file_length + * file_size + * get_dir + * link + * mkdir + * read_bytes + * read_file + * rename + * rm + * rmdir + * stat + * tail + * write_bytes + * write_file + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/link ds2.1/lib/doc/efun/filesystem/link *** ds1.1/lib/doc/efun/filesystem/link Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/link Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + link - link a file to another + + void link( string original, string reference ); + + Creates a link 'reference' to the file 'original'. This efun causes + valid_link(original, reference) to be called in the master object. If + valid_link() returns 0, the link() call fails. If valid_link() returns 1 + then the link() suceeds iff rename() would succeed if called with the same + arguments. + + See also: + rm, + rmdir, + rename, + mkdir, + cp + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/mkdir ds2.1/lib/doc/efun/filesystem/mkdir *** ds1.1/lib/doc/efun/filesystem/mkdir Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/mkdir Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + mkdir - make a directory + + int mkdir( string directory ); + + Creates the specified directory. Returns 1 if successful, 0 if not. + + See also: + rm, + rmdir, + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/read_bytes ds2.1/lib/doc/efun/filesystem/read_bytes *** ds1.1/lib/doc/efun/filesystem/read_bytes Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/read_bytes Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + read_bytes - reads a contiguous series of bytes from a file into a string + + string read_bytes( string path, int start, int length ); + + This function reads 'length' bytes beginning at byte # 'start' in the + file named 'path'. The bytes are returned as a string. Note that + (start + length) must not be past the end of the file or else read_bytes + will fail. If the second and third arguments are omitted, the entire file + is returned. + + See also: + read_file, + write_bytes diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/read_file ds2.1/lib/doc/efun/filesystem/read_file *** ds1.1/lib/doc/efun/filesystem/read_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/read_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + read_file - read a file into a string + + string read_file( string file, int start_line, int number_of_lines ); + + Read a line of text from a file into a string. The second and third + arguments are optional. If only the first argument is specified, the + entire file is returned (as a string). + + The start_line is the line number of the line you wish to read. This routine + will return 0 if you try to read past the end of the file, or if you try to + read from a nonpositive line. + + See also: + write_file, + read_buffer diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/rename ds2.1/lib/doc/efun/filesystem/rename *** ds1.1/lib/doc/efun/filesystem/rename Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/rename Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + rename - rename a file + + int rename( string src, string dst ); + + Renames the file 'src' to 'dst'. + + rename() returns zero (0) to indicate success. Nonzero indicates failure. + + See also: + rm, + rmdir, + cp, + link diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/rm ds2.1/lib/doc/efun/filesystem/rm *** ds1.1/lib/doc/efun/filesystem/rm Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/rm Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + rm - remove a file + + int rm( string file ); + + Remove file `file'. Returns 0 for failure and 1 for success. + + See also: + mkdir, + rmdir, + link + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/rmdir ds2.1/lib/doc/efun/filesystem/rmdir *** ds1.1/lib/doc/efun/filesystem/rmdir Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/rmdir Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + rmdir - remove a directory + + int rmdir( string dir ); + + Remove directory `dir'. + Returns nonzero for success, zero (0) for failure. + + See also: + rm, + mkdir, + link diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/stat ds2.1/lib/doc/efun/filesystem/stat *** ds1.1/lib/doc/efun/filesystem/stat Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/stat Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + stat - returns information pertaining to a file or a directory + + mixed stat(string str); + mixed stat(string str, int x); + + If str is the name of a regular file (not a directory), then stat() + will return an array of information pertaining to that file. The + form of the array is as follows: + + ({ file_size, last_time_file_touched, time_object_loaded }) + + If stat is called on a directory (not a regular file), or with a second + argument of -1, then stat() behaves identically to get_dir(). + + See also: + get_dir, + stat diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/tail ds2.1/lib/doc/efun/filesystem/tail *** ds1.1/lib/doc/efun/filesystem/tail Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/tail Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + tail - displays the latter portion of a file + + int tail( string path ); + + This efunction displays the latter portion of the file named by path. + It returns 1 if successful, 0 otherwise (e.g. when the file is protected + against reading). + + See also: + read_file, + read_buffer, + file_size diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/write_bytes ds2.1/lib/doc/efun/filesystem/write_bytes *** ds1.1/lib/doc/efun/filesystem/write_bytes Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/write_bytes Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + write_bytes - writes a contiguous series of bytes to a file + + int write_bytes( string path, int start, string series ); + + This function writes the bytes in 'series' into the file named by 'path' + beginning at byte # 'start'. It returns zero (0) upon failure, 1 otherwise. + + See also: + write_file, + read_bytes diff -c -r --new-file ds1.1/lib/doc/efun/filesystem/write_file ds2.1/lib/doc/efun/filesystem/write_file *** ds1.1/lib/doc/efun/filesystem/write_file Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/filesystem/write_file Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + write_file - appends a string to a file + + int write_file( string file, string str, int flag ); + + Append the string `str' into the file `file'. Returns 0 or 1 for + failure or success. If flag is 1, write_file overwrites instead of + appending. + + See also: + read_file, + write_buffer, + file_size diff -c -r --new-file ds1.1/lib/doc/efun/floats/acos ds2.1/lib/doc/efun/floats/acos *** ds1.1/lib/doc/efun/floats/acos Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/acos Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + acos - return the arccosine of a float + + float acos( float f ); + + This efun is available only if PACKAGE_MATH is compiled in to the driver. + + Returns the arccosine of its argument, `f', measured in radians. + + See also: + asin, + atan, + cos, + sin, + tan diff -c -r --new-file ds1.1/lib/doc/efun/floats/asin ds2.1/lib/doc/efun/floats/asin *** ds1.1/lib/doc/efun/floats/asin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/asin Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + asin - return the arcsine of a float + + float asin( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the arcsine of its argument, `f', measured in radians. + + See also: + acos, + atan, + cos, + sin, + tan diff -c -r --new-file ds1.1/lib/doc/efun/floats/atan ds2.1/lib/doc/efun/floats/atan *** ds1.1/lib/doc/efun/floats/atan Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/atan Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + atan - return the tangent of a float + + float atan( float f ); + + This efun is only available if PACKAGE_MATH is not compiled in. + + Returns the arctangent of its argument, `f', measured in radians. + + See also: + acos, + asin, + cos, + sin, + tan diff -c -r --new-file ds1.1/lib/doc/efun/floats/ceil ds2.1/lib/doc/efun/floats/ceil *** ds1.1/lib/doc/efun/floats/ceil Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/ceil Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + ceil - round a float up to the nearest integer + + float ceil( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns (as a float) the nearest integer number equal to or greater than f. + + See also: + floor, + to_int, + to_float + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/floats/cos ds2.1/lib/doc/efun/floats/cos *** ds1.1/lib/doc/efun/floats/cos Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/cos Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + cos - return the cosine of a float + + float cos( float f ); + + This efun is only available if PACKAGE_MATH is compiled into the driver. + + Returns the cosine of its argument, `f', measured in radians. + + See also: + acos, + asin, + atan, + sin, + tan + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/floats/exp ds2.1/lib/doc/efun/floats/exp *** ds1.1/lib/doc/efun/floats/exp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/exp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + exp - find e to the power of a float + + float exp( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + exp() returns e^f. + + See also: + log, + pow, + sqrt + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/floats/floor ds2.1/lib/doc/efun/floats/floor *** ds1.1/lib/doc/efun/floats/floor Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/floor Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + floor - round a float down to the nearest integer + + float floor( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns (as a float) the nearest integer number equal to or smaller than f. + + See also: + ceil, + to_int, + to_float diff -c -r --new-file ds1.1/lib/doc/efun/floats/index ds2.1/lib/doc/efun/floats/index *** ds1.1/lib/doc/efun/floats/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + Float Efuns + + The following efuns provide general math library functions. + + <DL> + * acos + * asin + * atan + * ceil + * cos + * exp + * floatp + * floor + * log + * pow + * sin + * sqrt + * tan + * to_int + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/floats/log ds2.1/lib/doc/efun/floats/log *** ds1.1/lib/doc/efun/floats/log Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/log Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + log - returns the natural logarithm of a float + + float log( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the natural logarithm of its argument, `f'. `f' must be positive. + + See also: + exp, + pow, + sqrt diff -c -r --new-file ds1.1/lib/doc/efun/floats/pow ds2.1/lib/doc/efun/floats/pow *** ds1.1/lib/doc/efun/floats/pow Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/pow Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + pow - find an exponent of a float + + float pow( float x, float y ); + + This efun is only available if PACKAGE_MATH is defined. + + pow() returns x to the y power. If x is 0.0, y must be positive. If x is + negative, y must be an integer. + + See also: + exp, + log, + sqrt diff -c -r --new-file ds1.1/lib/doc/efun/floats/sin ds2.1/lib/doc/efun/floats/sin *** ds1.1/lib/doc/efun/floats/sin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/sin Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + sin - return the sine of a float + + float sin( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the sine of its argument, `f', measured in radians. + + See also: + acos, + asin, + atan, + cos, + tan + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/floats/sqrt ds2.1/lib/doc/efun/floats/sqrt *** ds1.1/lib/doc/efun/floats/sqrt Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/sqrt Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + sqrt - returns the square root of a float + + float sqrt( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + sqrt() returns the non-negative square root of its argument, `f'. The value + of `f' must not be negative. + + See also: + exp, + log, + pow + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/floats/tan ds2.1/lib/doc/efun/floats/tan *** ds1.1/lib/doc/efun/floats/tan Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/tan Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + tan - return the tangent of a float + + float tan( float f ); + + This efun is only available if PACKAGE_MATH is compiled in. + + Returns the tangent of its argument, 'f', measured in radians. + + See also: + acos, + asin, + atan, + cos, + sin diff -c -r --new-file ds1.1/lib/doc/efun/floats/to_int ds2.1/lib/doc/efun/floats/to_int *** ds1.1/lib/doc/efun/floats/to_int Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/floats/to_int Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + to_int - convert a float or buffer to an int + + int to_int( float x ); + int to_int( buffer x ); + int to_int( string x ); + + If 'x' is a float, the to_int() call returns the number of type 'int' that is + equivalent to 'x' (with any decimal stripped off). If 'x' is a buffer, the + call returns the integer (in network-byte-order) that is embedded in the + buffer. If 'x' is a string, then the string is converted to an integer. + An undefined value is returned if the string is not a valid number. + + See also: + to_float, + read_buffer diff -c -r --new-file ds1.1/lib/doc/efun/functions/bind ds2.1/lib/doc/efun/functions/bind *** ds1.1/lib/doc/efun/functions/bind Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/functions/bind Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + bind - bind a function pointer to a new object + + function bind(function, object); + + bind() causes a function to become owned by the new object. This changes + the value of this_object() when the function pointer is evaluated. Functions + that reference global variables or functions in the object that created + them cannot be rebound. Binding a function to the object it is already + bound to will never fail. + + Permission to use this efun is controlled by the valid_bind() master apply. + + See also: + function_owner, + valid_bind diff -c -r --new-file ds1.1/lib/doc/efun/functions/evaluate ds2.1/lib/doc/efun/functions/evaluate *** ds1.1/lib/doc/efun/functions/evaluate Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/functions/evaluate Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + evaluate - evaluate a function pointer + + mixed evaluate(mixed f, ...); + + If f is a function, f is called with the rest of the arguments. + Otherwise, f is returned. evaluate(f, ...) is the same as (*f)(...). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/functions/function_owner ds2.1/lib/doc/efun/functions/function_owner *** ds1.1/lib/doc/efun/functions/function_owner Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/functions/function_owner Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + function_owner - return the owner of a given function. + + object function_owner(function); + + function_owner returns the object that owns the function specified by + the argument. + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + bind diff -c -r --new-file ds1.1/lib/doc/efun/functions/index ds2.1/lib/doc/efun/functions/index *** ds1.1/lib/doc/efun/functions/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/functions/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + Function efuns + + These efuns are for use with function pointers. + + <DL> + * bind + * evaluate + * functionp + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/general/copy ds2.1/lib/doc/efun/general/copy *** ds1.1/lib/doc/efun/general/copy Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/copy Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + copy - recursively duplicate a value + + mixed copy(mixed); + + copy() returns a value with exactly the same value as its argument, but with + all reference types (mappings, arrays, etc) duplicated. For example: + + mapping a, b = ({ 1 }); + a = b; + a[0] = 2; + printf("%O %O\n", a, b); + + results in ({ 2 }) and ({ 2 }), while: + + mapping a, b = ({ 1 }); + a = copy(b); + a[0] = 2; + printf("%O %O\n", a, b); + + results in ({ 2 }) and ({ 1 }). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/general/fetch_variable ds2.1/lib/doc/efun/general/fetch_variable *** ds1.1/lib/doc/efun/general/fetch_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/fetch_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + fetch_variable - set the value of a variable + + mixed fetch_variable(string); + + Return the value of the variable specified by the argument. + Note that the variable must be defined, and must be defined in this_object(). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + restore_variable, + store_variable, + restore_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/general/filter ds2.1/lib/doc/efun/general/filter *** ds1.1/lib/doc/efun/general/filter Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/filter Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + filter - select certain elements + + mixed filter(mixed x, string fun, object ob, mixed extra, ...); + + mixed filter(mixed x, function f, mixed extra, ...); + + The (ob, fun) syntax works as if (: call_other, ob, fun :) had been passed as + f. Filter returns a new structure containing only the elements of x for which + the function returns nonzero. Currently, it can be used on arrays and + mappings. In the case of mappings, both the key and the value are passed + to the function. extra and all the following arguments are passed to the + function after the element. For example, filter(arr, fun, 2, 3) will + first call fun(arr[0], 2, 3) then fun(arr[1], 2, 3) etc. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/general/index ds2.1/lib/doc/efun/general/index *** ds1.1/lib/doc/efun/general/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + Efuns for general LPC values + + These efuns act on arbitrary values of various types. + + <DL> + * copy + * fetch_variable + * filter + * map + * restore_variable + * save_variable + * store_variable + * sizeof + * typeof + * undefinedp + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/general/map ds2.1/lib/doc/efun/general/map *** ds1.1/lib/doc/efun/general/map Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/map Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + map - modify an mapping + + mixed map( mixed x, string fun, object ob, mixed extra, ... ); + + mixed map( mixed x, function f, mixed extra, ... ); + + The (ob, fun) syntax works as if (: call_other, ob, fun :) had been passed as + f. Map returns a new structure containing the return values of f being applied + to each element of x. Currently, it can be used on arrays, mappings and + strings. In the case of mappings, both the key and the value are passed + to the function. In the case of strings, the characters are passed to the + function one at a time as ints. extra and all the following arguments are + passed to the function after the element. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/general/restore_variable ds2.1/lib/doc/efun/general/restore_variable *** ds1.1/lib/doc/efun/general/restore_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/restore_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + restore_variable - restore value of a variable from a string + + mixed restore_variable( string value ); + + Restores an LPC value from a string. The format used is the + same format as save/restore_object. + + See also: + save_variable, + restore_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/general/save_variable ds2.1/lib/doc/efun/general/save_variable *** ds1.1/lib/doc/efun/general/save_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/save_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + save_variable - save the value of variable into a string + + string save_variable( mixed var ); + + Saves an LPC value into a string. The format is the same as + save/restore_object. + + See also: + restore_variable, + restore_object diff -c -r --new-file ds1.1/lib/doc/efun/general/sizeof ds2.1/lib/doc/efun/general/sizeof *** ds1.1/lib/doc/efun/general/sizeof Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/sizeof Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + sizeof - return the number of elements in an array + + int sizeof( mixed var ); + + Return the number of elements in an array, mapping, string, class or + buffer 'var'. If `var' is not an array, mapping, string, class or + buffer, then zero (0) is returned. + + See also: + strlen diff -c -r --new-file ds1.1/lib/doc/efun/general/store_variable ds2.1/lib/doc/efun/general/store_variable *** ds1.1/lib/doc/efun/general/store_variable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/store_variable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + store_variable - set the value of a variable + + void store_variable(string, mixed); + + Set the value of the variable specified by the first argument to the value + specfied by the second argument. Note that the variable must be defined, and + must be defined in this_object(). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + restore_variable, + fetch_variable, + save_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/general/typeof ds2.1/lib/doc/efun/general/typeof *** ds1.1/lib/doc/efun/general/typeof Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/general/typeof Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + typeof - return the type of an expression + + int typeof( mixed var ); + + Return the type of an expression. The return values are given in + the driver include "type.h". They are: + + <pre> + INT "int" + STRING "string" + ARRAY "array" + OBJECT "object" + MAPPING "mapping" + FUNCTION "function" + FLOAT "float" + BUFFER "buffer" + CLASS "class" + </pre> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/add_action ds2.1/lib/doc/efun/interactive/add_action *** ds1.1/lib/doc/efun/interactive/add_action Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/add_action Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,49 ---- + add_action - bind a command verb to a local function + + void add_action( string | function fun, string | string array cmd ); + + void add_action( string | function fun, string | string array cmd, int flag ); + + This efun is only available if NO_ADD_ACTION isn't defined. + + Set up a function 'fun' to be called the a user types the command 'cmd'. + (What is the command is determined by the first 'word' which consists + of all the characters before the first space, with the exception of + verbs that don't need a space; see below). + + If 'cmd' is an array, then that function will be called for any of the + commands in the array. 'fun' can either be a string which is the name + of a function in the object adding the command, or a function pointer. + + Functions called by a user command will get the rest of the command line + as a string. It must then return 0 if it was the wrong command, otherwise 1. + If 1 is returned, no further parsing is done; if 0 is returned, other + commands will be checked (possibly the same command added by a different + object). If no command is found, the default error message will be sent + to the player (traditionally, 'What?' but see also notify_fail()) + + For functions which can be called by more than one command, check query_verb() + to see which command was used. + + Note: add_action() does not add commands globally; it only adds commands to + this_user(), and the object must be 'close' to the user it is adding commands + to. + + Usually add_action() is called only from an init() routine. The object that + defines commands must be 'close' to the user, either being the user, + being carried by the user, being the room around the user, or being an + object in the same room as the user. + + Since init() is called when a user moves 'close' to an object, it is a + convenient time to add such commands. The commands are removed when the + user moves out of range (or the object does). + + If argument 'flag' is 1, then only the leading characters of the command has + to match the verb 'cmd' and the entire verb is returned by query_verb(). If + argument 'flag' is 2, then again, only the leading characters must match, + but query_verb() will only return the characters following 'cmd'. + + See also: + query_verb, + remove_action, + init diff -c -r --new-file ds1.1/lib/doc/efun/interactive/command ds2.1/lib/doc/efun/interactive/command *** ds1.1/lib/doc/efun/interactive/command Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/command Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + command - execute a command as if given by the object + + int command( string str ); + + This efun is only available if NO_ADD_ACTION isn't defined. + + Execute 'str' for the object this_object() as a command (matching against + add_actions and such). The object must have called enable_commands() for + this to have any effect. + In case of failure, 0 is returned, otherwise a numeric value is returned, + which is the LPC "evaluation cost" of the command. Bigger numbers mean + higher cost, but the whole scale is subjective and unreliable. + + See also: + add_action, + enable_commands diff -c -r --new-file ds1.1/lib/doc/efun/interactive/commands ds2.1/lib/doc/efun/interactive/commands *** ds1.1/lib/doc/efun/interactive/commands Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/commands Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + commands - returns some information about actions the user can take + + array commands(); + + This efun is only available if NO_ADD_ACTION is not defined. + + Returns an array of an array of 4 items describing the actions that + are available to this_object(). The first item is the command + itself (as passed to add_action()). The second is the set of + flags (passed to add_action as the third argument, often defaulted + to 0). The third is the object that defined the action. The fourth + is the function to be called ("<function>" if it is a function pointer). + + See also: + add_action, + enable_commands, + disable_commands diff -c -r --new-file ds1.1/lib/doc/efun/interactive/disable_commands ds2.1/lib/doc/efun/interactive/disable_commands *** ds1.1/lib/doc/efun/interactive/disable_commands Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/disable_commands Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + disable_commands - makes a living object non-living + + void disable_commands(); + + This efun is only available if NO_ADD_ACTION is not defined. + + Causes the current object to no longer be able to execute commands. + + See also: + enable_commands diff -c -r --new-file ds1.1/lib/doc/efun/interactive/disable_wizard ds2.1/lib/doc/efun/interactive/disable_wizard *** ds1.1/lib/doc/efun/interactive/disable_wizard Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/disable_wizard Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + disable_wizard - remove wizard priveleges from an object + + void disable_wizard(); + + This efun is only available if NO_WIZARDS is not defined. + + The opposite of enable_wizard(). Disables wizard privileges from the + current object. + + See also: + enable_wizard, + wizardp diff -c -r --new-file ds1.1/lib/doc/efun/interactive/ed ds2.1/lib/doc/efun/interactive/ed *** ds1.1/lib/doc/efun/interactive/ed Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/ed Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,39 ---- + ed - edit a file + + This efun is only available if OLD_ED is defined. + + void ed( string file, string exit_fn, int restricted ); + + void ed( string file, string write_fn, string exit_fn, int restricted ); + + This is a funny function. It will start a local editor on an optional + file. This editor is almost UNIX ed compatible. When in the editor + type 'h' for help. + + The 'write_fn' function allows the mudlib to handle file locks and + administrative logging of files modified. When the editor writes to a + file, the driver will callback the 'write_fn' function twice. The first + time, the function is called before the + write takes place -- 'flag' will be 0. If the function returns 1, + the write will continue, + otherwise it will abort. The second time, the function is called + after the write has completed -- 'flag' will be non-zero. + This callback function should have the form: + + int write_fn(string fname, int flag) + + When the editor is exited, the driver will callback the 'exit_fn' + function. This function allows the mudlib to clean up. This + callback function has the form: + + void exit_fn() + + The optional 'restricted' flag limits the editor's + capabilities, such as inserting a file, and saving using an alternate + file name. + + See also: + regexp, + valid_read, + valid_write, + get_save_file_name diff -c -r --new-file ds1.1/lib/doc/efun/interactive/ed_cmd ds2.1/lib/doc/efun/interactive/ed_cmd *** ds1.1/lib/doc/efun/interactive/ed_cmd Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/ed_cmd Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + ed_cmd - perform an 'ed' command + + This efun is only available if OLD_ED is not defined. + + string ed_cmd(string cmd); + + Performs the ed command 'cmd'. The result of the command is returned. + Ed must have been started with ed_start() in order to call this efun. + + See also: + ed_start diff -c -r --new-file ds1.1/lib/doc/efun/interactive/ed_start ds2.1/lib/doc/efun/interactive/ed_start *** ds1.1/lib/doc/efun/interactive/ed_start Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/ed_start Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + ed_start - start up 'ed' + + This efun is only available if OLD_ED is not defined. + + string ed_start(string file, int flag); + + string ed_start(string file); + + string ed_start(); + + If 'flag' is nonzero, ed is started in restricted mode. See the documentation + for the old efun for information. 'file' is the name of the file to open; + if none is given then no file becomes active. + + ed_start() may not be called when another ed session for the current + object is already active. Any messages generated while starting up ed + are returned by this efun. + + See also: + ed, + ed_cmd, + query_ed_mode diff -c -r --new-file ds1.1/lib/doc/efun/interactive/enable_commands ds2.1/lib/doc/efun/interactive/enable_commands *** ds1.1/lib/doc/efun/interactive/enable_commands Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/enable_commands Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + enable_commands - allow object to use 'player' commands + + void enable_commands(); + + This efun is only available if NO_ADD_ACTION is not defined. + + enable_commands() marks this_object() as a living object, and allows + it to use commands added with add_action() (by using command()). + When enable_commands() is called, the driver also looks for the + local function catch_tell(), and if found, it will call it every time + a message (via say() for example) is given to the object. + + See also: + living, + add_action, + command, + catch_tell, + say diff -c -r --new-file ds1.1/lib/doc/efun/interactive/enable_wizard ds2.1/lib/doc/efun/interactive/enable_wizard *** ds1.1/lib/doc/efun/interactive/enable_wizard Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/enable_wizard Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,29 ---- + enable_wizard - give wizard priveleges to an object + + void enable_wizard(); + + Available only if NO_WIZARDS isn't defined. + + Any interactive object that calls enable_wizard() will cause wizardp() + to return true if called on that object. enable_wizard() gives three + privileges to the interactive object in question: + + <DL> + * ability to use restricted modes of ed when the RESTRICTED_ED option + is compiled into the driver. + * + privilege of receiving descriptive runtime error messages. + * + privilege of using the trace() and traceprefix() efuns. + <DL> + + If you don't use this, ed() must be explicitly restricted when necessary, + an error_handler should be implemented to give appropriate messages if you + don't want all users to get descriptive error traces, and trace() and + traceprefix() should be restricted via simul_efuns, if necessary. + + See also: + disable_wizard, + wizardp + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/exec ds2.1/lib/doc/efun/interactive/exec *** ds1.1/lib/doc/efun/interactive/exec Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/exec Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + exec - switches a user (interactive) connection from one object to another + + int exec( object to, object from ); + + This efunction allows the interactive link to a given object to be + moved to another object. That is, after a successful exec(to, from) + call, interactive(to) will return 1 and interactive(from) will return 0. + The player that was controlling 'from' will begin controlling 'to' following + the exec() call. Note that this is a powerful function and its use must + be restricted if you wish to attempt to have a secure mud. The proper + way to restrict the use of exec() is to make a simul_efun of the same name + and then use valid_override() to restrict the use of a simul_efun override + (i.e. efun::exec()). The exec() function returns 1 if the switch is + successful (and 0 otherwise). + + See also: + interactive, + valid_override diff -c -r --new-file ds1.1/lib/doc/efun/interactive/find_player ds2.1/lib/doc/efun/interactive/find_player *** ds1.1/lib/doc/efun/interactive/find_player Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/find_player Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + find_player - find a player by name + + object find_player( string str ); + + This efun is only available when NO_ADD_ACTION is not defined. + + Similar to find_living(), but only searches through objects that are + interactive, or were once interactive. + + See also: + find_living, + livings, + users, + set_living_name diff -c -r --new-file ds1.1/lib/doc/efun/interactive/get_char ds2.1/lib/doc/efun/interactive/get_char *** ds1.1/lib/doc/efun/interactive/get_char Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/get_char Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,28 ---- + get_char - causes next character of input to be sent to a specified function + + varargs void get_char( string | function fun, int flag, ... ); + + Enable next character of user input to be sent to the function `fun' as + an argument. The input character will not be parsed by the driver. + + Note that get_char is non-blocking which means that the object calling + get_char does not pause waiting for input. Instead the object continues + to execute any statements following the get_char. The specified function + `fun' will not be called until the user input has been collected. + + If "get_char()" is called more than once in the same execution, only the + first call has any effect. + + If optional argument `flag' is non-zero, the char given by the player will + not be echoed, and is not seen if snooped (this is useful for collecting + passwords). + + The function `fun' will be called with the user input as its first argument + (a string). Any additional arguments supplied to get_char will be passed on to + `fun' as arguments following the user input. + + See also: + call_out, + input_to + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/in_edit ds2.1/lib/doc/efun/interactive/in_edit *** ds1.1/lib/doc/efun/interactive/in_edit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/in_edit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + in_edit() - determine if a player is in the editor + + string in_edit(); + + string in_edit(object ob); + + If the given object is in the editor, the file being edited is + returned, else zero. If no object is given, this_object() is used. + + See also: + ed, + in_input + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/in_input ds2.1/lib/doc/efun/interactive/in_input *** ds1.1/lib/doc/efun/interactive/in_input Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/in_input Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + in_input() - determines if a player is inputting to an input_to + + int in_input(); + + int in_input(object ob); + + Returns 1 if the object is currently inputting to an input_to or get_char. + If no object is specified, this_object() is assumed. + + See also: + get_char, + input_to + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/interactive/index ds2.1/lib/doc/efun/interactive/index *** ds1.1/lib/doc/efun/interactive/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,72 ---- + Interactive efuns + + <H3>These efuns are for dealing with interactive (user) objects:</H3> + + actions and related efuns: (Not available with NO_ADD_ACTION) + + <DL> + * add_action + * command + * commands + * disable_commands + * enable_commands + * find_player + * notify_fail + </DL> + + Archaic wizard functions: (Not available with NO_WIZARDS) + <DL> + * disable_wizard + * enable_wizard + * wizardp + </DL> + + The old ed interface: (#define OLD_ED) + <DL> + * ed + * in_edit + </DL> + + The new one: + <DL> + * ed_cmd + * ed_start + * in_edit + * query_ed_mode + </DL> + + Input handling: + <DL> + * get_char + * input_to + * in_input + * receive + </DL> + + Output handling: + <DL> + * printf + * say + * shout + * snoop + * write + </DL> + + Information about user objects, and miscellaneous utility functions: + <DL> + * exec + * interactive + * message + * query_host_name + * query_idle + * query_ip_name + * query_ip_number + * query_snoop + * query_snooping + * resolve + * this_interactive + * this_player + * userp + * users + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/input_to ds2.1/lib/doc/efun/interactive/input_to *** ds1.1/lib/doc/efun/interactive/input_to Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/input_to Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,33 ---- + input_to - causes next line of input to be sent to a specified function + + varargs void input_to( string | function fun, int flag, ... ); + + Enable next line of user input to be sent to the local function 'fun' as + an argument. The input line will not be parsed by the driver. + + Note that input_to is non-blocking which means that the object calling + input_to does not pause waiting for input. Instead the object continues + to execute any statements following the input_to. The specified function + 'fun' will not be called until the user input has been collected. + + If "input_to()" is called more than once in the same execution, only the + first call has any effect. + + If optional argument 'flag' has the 1 bit set, the line given by the player + will not be echoed, and is not seen if snooped (this is useful for collecting + passwords). + + If 'flag' has the 2 bit set, the input_to cannot be bypassed by beginning the + command with '!'. Otherwise, lines which start with '!' drop through to + the normal input handler. + + The function 'fun' will be called with the user input as its first argument + (a string). Any additional arguments supplied to input_to will be passed on to + 'fun' as arguments following the user input. + + See also: + call_other, + call_out, + get_char + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/interactive ds2.1/lib/doc/efun/interactive/interactive *** ds1.1/lib/doc/efun/interactive/interactive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/interactive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + interactive - detects whether or not a given object is an interactive + + int interactive( object ob ); + + Return non-zero if 'ob' is an interactive player. 0 will be returned + if he is link dead. + + See also: + query_ip_number, + query_ip_name, + enable_commands + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/message ds2.1/lib/doc/efun/interactive/message *** ds1.1/lib/doc/efun/interactive/message Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/message Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,32 ---- + message - deliver messages to "living" objects + + void message( mixed class, mixed message, mixed target, mixed exclude ); + + message() calls receive_message(mixed class, mixed message) in all objects + in the target list excluding those in the exclude list. This basically + tells the object the message. + + Class is the type of message (used for clients and such). An example + would be 'combat', 'shout', 'emergency' etc. Any LPC value can be + passed, though. + + Message is usually a string containing the text to send, though it + can also be any value. + + Target is a list of objects to be sent the message. This can be either a + single object string or object pointer, or may be an array of either. + If a target is non-living all objects in its environment will receive + the message. + + Exclude is a list of objects that should not receive the message. This + can either be one object or an array of objects. + + See also: + receive_message, + say, + write, + shout, + tell_object, + tell_room + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/notify_fail ds2.1/lib/doc/efun/interactive/notify_fail *** ds1.1/lib/doc/efun/interactive/notify_fail Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/notify_fail Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,36 ---- + notify_fail - set the default error message to a specified string + + int notify_fail( string | function str ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Store `str' as the error message to be returned instead of the default message + `What?'. The message will be displayed if a 0 is returned from all actions + setup via add_action(). This is the preferred way to display error messages + since it allows other objects a chance to respond to the same verb (command). + Do not use write() to display the error message since this will require you + to return a 1 (unless you want to see the result of the write() in addition to + the 'What?' message). However, if you do return a 1, then no other objects + will get a chance to respond to the user command. + + Note: Getting this right in the presence of multiple failures is tricky, + to say the least. One can use a function pointer instead, and have the + routine resolve the collisions. + + If a function is passed instead of a string, the function is called + instead of printing a message. If the function returns a string, that + string is used as the failure message. Also, this_player() is set + correctly, so write() can be used. + + If "notify_fail()" is called more than once, only the last call will have + an effect. + + The idea behind this function is to allow better error messages than + `What?'. + + As a side note, notify_fail() always returns zero, so return notify_fail(...) + works as expected. + + add_action + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/printf ds2.1/lib/doc/efun/interactive/printf *** ds1.1/lib/doc/efun/interactive/printf Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/printf Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,75 ---- + printf - formatted output conversion + + void printf( string format, ... ); + + The output is sent to this_user(), in the same manner as the write() efun. + Implemented by Lynscar (Sean A Reith). + + This version supports the following as modifiers: + <DL> + * " " - pad positive integers with a space. + * "+" - pad positive integers with a plus sign. + * "-" - left adjusted within field size. + + Note: std (s)printf() defaults to right justification, which is unnatural + in the context of a mainly string based language but has been retained for + "compatability". + * "|" - centered within field size. + * "=" - column mode if strings are greater than field size. This is only + meaningful with strings, all other types ignore this. Columns are + auto-magically word wrapped. + * "#" - table mode, print a list of '\\n' separated 'words' in a + table within the field size. only meaningful with strings. + * a number - + specifies the field size, a '*' specifies to use the corresponding + arg as the field size. If n is prepended with a zero, then is padded + zeros, else it is padded with spaces (or specified pad string). + * "." followed by a number - + precision of n, simple strings truncate after this (if precision is + greater than field size, then field size = precision), tables use + precision to specify the number of columns (if precision not specified + then tables calculate a best fit), all other types ignore this. + * ":" followed by a number - + n specifies the fs _and_ the precision, if n is prepended by a zero + then it is padded with zeros instead of spaces. + * "@" - + the argument is an array. the corresponding format_info (minus the + "@") is applyed to each element of the array. + * "'X'" - + The char(s) between the single-quotes are used to pad to field + size (defaults to space) (if both a zero (in front of field + size) and a pad string are specified, the one specified second + overrules). NOTE: to include "'" in the pad string, you must + use "\'" (as the backslash has to be escaped past the + interpreter), similarly, to include "\" requires "\\\\". + </DL> + + The following are the possible type specifiers. + <DL> + * % - + in which case no arguments are interpreted, and a "%" is inserted, and + all modifiers are ignored. + * O - + the argument is an LPC datatype. The format is suitable for printing any + type (useful for debugging) + * s - + the argument is a string. + * d or i - + the integer arg is printed in decimal. + * c - + the integer arg is to be printed as a character. + * o - + the integer arg is printed in octal. + * x - + the integer arg is printed in hex. + * X - + the integer arg is printed in hex (with A-F in capitals). + * f - + floating point number + </DL> + + See also: + sscanf, + sprintf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_ed_mode ds2.1/lib/doc/efun/interactive/query_ed_mode *** ds1.1/lib/doc/efun/interactive/query_ed_mode Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_ed_mode Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + query_ed_mode - return which mode ed is in + + This efun is only available if OLD_ED is not defined. + + int query_ed_mode(); + + Return value should be interpreted as follows: + + 0 = normal ed prompt + + -1 = not in ed + + -2 = more prompt for help + + positive number = prompt for input for line n + + See also: + ed, + ed_start + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_host_name ds2.1/lib/doc/efun/interactive/query_host_name *** ds1.1/lib/doc/efun/interactive/query_host_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_host_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + query_host_name - return the host name + + string query_host_name(); + + query_host_name() returns the name of the host. + + See also: + resolve, + socket_address, + query_ip_name, + query_ip_number + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_idle ds2.1/lib/doc/efun/interactive/query_idle *** ds1.1/lib/doc/efun/interactive/query_idle Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_idle Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + query_idle - determine how many seconds an interactive player has been idle + + int query_idle( object ob ); + + Query how many seconds a player object (ob) has been idling. + + See also: + in_edit, + in_input + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_ip_name ds2.1/lib/doc/efun/interactive/query_ip_name *** ds1.1/lib/doc/efun/interactive/query_ip_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_ip_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + query_ip_name - return the ip name of a given player object. + + string query_ip_name( object ob ); + + Return the IP address for player `ob'. An asynchronous process `addr_server' + is used to find out these name in parallel. If there are any failures to + find the ip-name, then the ip-number is returned instead. + + See also: + query_ip_number, + query_host_name, + resolve, + socket_address + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_ip_number ds2.1/lib/doc/efun/interactive/query_ip_number *** ds1.1/lib/doc/efun/interactive/query_ip_number Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_ip_number Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + query_ip_number - return the ip number for a player object + + string query_ip_number( object ob ); + + Return the ip-number (dotted decimal form) for player `ob'. + + See also: + query_ip_name, + query_host_name, + resolve, + socket_address + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_ip_port ds2.1/lib/doc/efun/interactive/query_ip_port *** ds1.1/lib/doc/efun/interactive/query_ip_port Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_ip_port Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + query_ip_port - return the ip port of a given player object. + + int query_ip_port(object | void); + + Returns the local port that the argument object used to connect to + the mud. If the argument is void, return the local port that + this_player() used to connect to the mud. Calling this on + non-interactive objects will return 0. + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + query_ip_name, + query_host_name, + resolve, + socket_address + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_notify_fail ds2.1/lib/doc/efun/interactive/query_notify_fail *** ds1.1/lib/doc/efun/interactive/query_notify_fail Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_notify_fail Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + query_notify_fail - Query if an interactive object has a pending notify_fail() + + mixed query_notify_fail(void); + + This function returns whatever this_player()'s notify_fail value + has been set to. This is either a string, or a function, depending + on what it has been set to by the most recent call to notify_fail() + that applied to this_player(). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + This function also requires that the NO_ADD_ACTION option NOT be defined. + + See also: + add_action, + notify_fail + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_snoop ds2.1/lib/doc/efun/interactive/query_snoop *** ds1.1/lib/doc/efun/interactive/query_snoop Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_snoop Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + query_snoop - return the snooper of an interactive object + + object query_snoop( object ob ); + + If `ob' (an interactive object) is being snooped by another interactive object, + the snooping object is returned. Otherwise, 0 is returned. + + See also: + snoop, + query_snooping diff -c -r --new-file ds1.1/lib/doc/efun/interactive/query_snooping ds2.1/lib/doc/efun/interactive/query_snooping *** ds1.1/lib/doc/efun/interactive/query_snooping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/query_snooping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + query_snooping - return the object than an object is snooping + + object query_snooping( object ob ); + + If `ob' (an interactive object) is snooping another interactive object, the + snooped object is returned. Otherwise, 0 is returned. + + See also: + snoop, + query_snoop + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/receive ds2.1/lib/doc/efun/interactive/receive *** ds1.1/lib/doc/efun/interactive/receive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/receive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + receive - displays a message to the current object + + int receive( string message ); + + This efun is an interface to the add_message() function in the driver. + Its purpose is to display a message to the current object. It returns 1 + if the current object is interactive, 0 otherwise. Often, receive() is + called from within catch_tell() or receive_message(). + + See also: + catch_tell, + receive_message, + message + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/remove_action ds2.1/lib/doc/efun/interactive/remove_action *** ds1.1/lib/doc/efun/interactive/remove_action Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/remove_action Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + remove_action - unbind a command verb from a local function + + int remove_action( string fun, string cmd ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + remove_action() unbinds a verb cmd from an object function fun. Basically, + remove_action() is the complement to add_action(). When a + verb is no longer required, it can be unbound with remove_action(). + + remove_action() returns 1 on success and 0 on failure. + + See also: + add_action, + query_verb, + init + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/remove_interactive ds2.1/lib/doc/efun/interactive/remove_interactive *** ds1.1/lib/doc/efun/interactive/remove_interactive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/remove_interactive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + remove_interactive - disconnect an interactive object. + + int remove_interactive(object); + + If the argument object is interactive, and not destructed, cause it to + be disconnected. (i.e lose it's interactive status). Returns 1 if + the operation succeeded, or 0 if it didn't ( object destructed, or not + interactive) + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/resolve ds2.1/lib/doc/efun/interactive/resolve *** ds1.1/lib/doc/efun/interactive/resolve Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/resolve Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + resolve - resolve an internet address to domain name + + int resolve( string address, string callback_func ); + + resolve() resolves `address', which should be an internet address in the form + "127.0.0.1" or a domain name, into its domain name, or internet address. + When the resolve is complete, `callback_func' will be called in the + current object. The form of the callback is: + + void callback(string address, string resolved, int key); + + `key' will match up with the number that the call to resolve() returned. + `address' will be the domain name of the host, and `resolved' the dotted + decimal ip address. The unknown value will be 0 if the lookup failed. + + See also: + query_host_name, + socket_address, + query_ip_name, + query_ip_number + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/say ds2.1/lib/doc/efun/interactive/say *** ds1.1/lib/doc/efun/interactive/say Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/say Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + say - send a message to all users in the same environment + + varargs void say( string str, object | object array ); + + Sends a message to the environment of the originator, all items in the + same environment, and all items inside of the originator. The originator + is this_player(), unless this_player() == 0, in which case, the originator + is this_object(). + + The second argument is optional. If second argument `obj' is specified, + the message is sent to all except `obj'. If `obj' is not an object, but + an array of objects, all those objects are excluded from receiving the + message. + + See also: + message, + write, + shout, + tell_object, + tell_room + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/set_this_player ds2.1/lib/doc/efun/interactive/set_this_player *** ds1.1/lib/doc/efun/interactive/set_this_player Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/set_this_player Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_this_player - change the value of the current command giver. + + void set_this_player(object); + + This function changes the value of what this_player() returns during the + current execution. If the argument is an object, this_player() will return + the argument object. If it is an int, this_player() will return 0. + + This function requires the NO_ADD_ACTION option be defined in the + options file. + + See also: + this_player + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/shout ds2.1/lib/doc/efun/interactive/shout *** ds1.1/lib/doc/efun/interactive/shout Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/shout Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + shout - sends a message to all living objects + + void shout( string str ); + + Sends the string `str' to all living objects except this_player(). + + See also: + message, + write, + tell_object, + tell_room, + say + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/interactive/snoop ds2.1/lib/doc/efun/interactive/snoop *** ds1.1/lib/doc/efun/interactive/snoop Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/snoop Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + snoop - snoop an interactive user + + varargs object snoop( object snooper, object snoopee ); + + When both arguments are used, begins snooping of `snoopee' by + `snooper'. If the second argument is omitted, turns off all snooping + by `snoopee'. Security for snoop() is normally controlled by a + simul_efun. snoop() returns `snoopee' if successful in the + two-argument case, and `snooper' if it was successful in the + single-argument case. A return of 0 indicates failure. + The 'snoopee' must be an interactive object; the snooper can be any + object. However, snooping with a non-interactive object is useless + unless the RECEIVE_SNOOP option is enabled, and the object defines + a RECEIVE_SNOOP function. + + See also: + query_snoop, + query_snooping + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/this_interactive ds2.1/lib/doc/efun/interactive/this_interactive *** ds1.1/lib/doc/efun/interactive/this_interactive Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/this_interactive Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + this_interactive - return the object representing the current player + + object this_interactive(); + + Return the object representing the player that caused the calling function + to be called. This returns what this_player() was originally even if + it changed later due to enable_commands() or command() + + See also: + this_player + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/this_player ds2.1/lib/doc/efun/interactive/this_player *** ds1.1/lib/doc/efun/interactive/this_player Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/this_player Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + this_player - return the object representing the current player + + object this_player( int flag ); + + this_player() is exactly the same as this_user(). + + See also: + this_user diff -c -r --new-file ds1.1/lib/doc/efun/interactive/this_user ds2.1/lib/doc/efun/interactive/this_user *** ds1.1/lib/doc/efun/interactive/this_user Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/this_user Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + this_user - return the object representing the current interactive + + Return the object representing the user that caused the calling function + to be called. Note that this_user() may return a different value than + this_object() even when called from within a user object. If this_user + is called as this_user(1) then the returned value will be the interactive + that caused the calling function to be called. this_user(1) may return + a different value than this_user() in certain cases (such as when command() + is used by an admin to force a user to perform some command). + + See also: + this_object diff -c -r --new-file ds1.1/lib/doc/efun/interactive/userp ds2.1/lib/doc/efun/interactive/userp *** ds1.1/lib/doc/efun/interactive/userp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/userp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + userp - determine if a given object was once interactive + + int userp( object ); + + Returns 1 if the arg was once interactive. + + See also: + interactive, + users, + living + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/users ds2.1/lib/doc/efun/interactive/users *** ds1.1/lib/doc/efun/interactive/users Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/users Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + users - return an array of objects containing all interactive players + + object array users(); + + Return an array of objects, containing all interactive players. + + See also: + livings, + children, + objects + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/wizardp ds2.1/lib/doc/efun/interactive/wizardp *** ds1.1/lib/doc/efun/interactive/wizardp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/wizardp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + wizardp - determines if a given object had enable_wizard() performed in it + + int wizardp( object ); + + This efun is only available if NO_WIZARDS is not compiled in. + + Returns 1 if the arg had enable_wizard() performed on it. + + See also: + disable_wizard, + enable_wizard + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/interactive/write ds2.1/lib/doc/efun/interactive/write *** ds1.1/lib/doc/efun/interactive/write Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/interactive/write Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + write() - send a message to current player + + void write( mixed str ); + + Write a message `str' to current player. `str' can also be a number, which + will be translated to a string. + + See also: + message, + tell_object, + tell_room, + shout, + say + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/cache_stats ds2.1/lib/doc/efun/internals/cache_stats *** ds1.1/lib/doc/efun/internals/cache_stats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/cache_stats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + cache_stats - report various driver and mudlib statistics + + string cache_stats(); + + This efun is only available if CACHE_STATS is defined in options.h at + driver build time. This efun returns a string containing a summary + of the statstics on the call_other() cache hit rate. + + See also: + opcprof, + mud_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/debug_info ds2.1/lib/doc/efun/internals/debug_info *** ds1.1/lib/doc/efun/internals/debug_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/debug_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,93 ---- + debug_info - display debug information + + string debug_info( int operation, ... ); + + string debug_info( 0, object ob ); + + string debug_info( 1, object ob ); + + string debug_info( 2, object ob ); + + This efun is only available if PACKAGE_DEVELOP is compiled into the driver. + + debug_info() is a general-purpose facility which may be used to debug the + MudOS driver. The debugging information requested is determined by the + first argument. Successive arguments are determine by the operation selected. + + The existing operations (0 , 1 and 2) require a second object type argument, + and may be used to display the various fields of the MudOS object structure. + + The following LPC code was used to generate the sample output: + + <pre> + + create() { + write(debug_info(0, this_object())); + } + </pre> + + gives: + + <pre> + O_HEART_BEAT : FALSE + O_IS_WIZARD : FALSE + O_ENABLE_COMMANDS : FALSE + O_CLONE : FALSE + O_DESTRUCTED : FALSE + O_SWAPPED : FALSE + O_ONCE_INTERACTIVE: FALSE + O_RESET_STATE : FALSE + O_WILL_CLEAN_UP : FALSE + O_WILL_RESET: TRUE + total light : 0 + next_reset : 720300560 + time_of_ref : 720299416 + ref : 2 + swap_num : -1 + name : 'u/c/cynosure/di0' + next_all : OBJ(bin/dev/_update) + This object is the head of the object list. + </pre> + + <hr> + + <pre> + + create() { + write(debug_info(1, this_object())); + } + </pre> + + gives: + + <pre> + program ref's 1 + Name u/c/cynosure/di1.c + program size 10 + num func's 1 (16) + num strings 0 + num vars 0 (0) + num inherits 0 (0) + total size 104 + </pre> + + <hr> + + <pre> + + create() { + write(debug_info(2, this_object())); + } + </pre> + + gives: + + <pre> + x: "foo" + </pre> + + See also: + dump_file_descriptors, + dump_socket_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/debugmalloc ds2.1/lib/doc/efun/internals/debugmalloc *** ds1.1/lib/doc/efun/internals/debugmalloc Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/debugmalloc Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + debugmalloc - dumps information on malloc'd memory to a file + + void debugmalloc(string filename, int mask); + + This efun is only available when PACKAGE_DEVELOP, DEBUGMALLOC and DEBUGMALLOC_EXTENSIONS are + both defined in options.h at driver build time. The debugmalloc() efun + will dump information on those chunks of memory allocated by DMALLOC() and + related macros if the bitwise and (&) with the tag supplied by the macro + (i.e. (mask & tag)) is non-zero. Read md.c and config.h in the + driver source for more information. + + See also: + set_malloc_mask + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/dump_file_descriptors ds2.1/lib/doc/efun/internals/dump_file_descriptors *** ds1.1/lib/doc/efun/internals/dump_file_descriptors Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/dump_file_descriptors Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,32 ---- + dump_file_descriptors - dump the MudOS process file descriptor table + + string dump_file_descriptors(); + + This function is provided to assist in debugging the MudOS driver and + helps overcome deficiencies in some UN*X implementations which do not + provide equivalent or superior debugging facilities as part of the + operating system itself. The interpretation of the output is very + system-dependent. Each file descriptor is checked to determine whether + it refers to an open file. If so, information is displayed from the + "stat structure" returned by the fstat() system call. + + The following output was produced on Lambda Realms running on a Sequent + DYNIX/ptx system: + + <pre> + Fd Device Number Inode Mode Uid Gid Size + -- ------------- ----- ------ ----- ----- ---------- + 0 3 2 10319 c 666 0 3 0 + 1 79 7 164598 f 644 2862 1 789522 + 2 79 7 164598 f 644 2862 1 789522 + 3 40 33b 6925 c 0 2862 1 0 + 4 40 2a4 6943 c 0 2862 1 0 + 5 79 7 164599 f 600 2862 1 44784 + 6 40 2e2 145996 c 0 2862 1 0 + 7 79 7 164601 f 644 2862 1 506 + </pre> + + See also: + dump_socket_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/dump_prog ds2.1/lib/doc/efun/internals/dump_prog *** ds1.1/lib/doc/efun/internals/dump_prog Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/dump_prog Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + dump_prog - dump/disassemble an LPC object + + void dump_prog( object ob, int flags, string file ); + + This efun is only available when PACKAGE_DEVELOP is compiled into the driver. + + dump_prog() dumps information about the program of `obj' to a file, + `file', or "/PROG_DUMP" if `file' is not given. If the current object + does not have write access to the file, it fails. + + Flags can be a combination of the following values: + <DL> + * 1 - include a disassembly of the i-code + * 2 - include line number information + </DL> + + See also: + debug_info, + dumpallobj + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/dump_socket_status ds2.1/lib/doc/efun/internals/dump_socket_status *** ds1.1/lib/doc/efun/internals/dump_socket_status Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/dump_socket_status Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,54 ---- + dump_socket_status - display the status of each LPC socket + + string dump_socket_status(); + + This efun is only available when PACKAGE_SOCKETS is compiled into the driver. + + dump_socket_status() is a diagnostic facility which displays the current + status of all LPC sockets configured into the MudOS driver. It is useful + for debugging LPC sockets applications. Each row in the output corresponds + to a single LPC socket. The first row corresponds to LPC socket descriptor 0, + the second row, 1, etc. The total number of sockets is configured when the + driver is built. + + The first column "Fd" is the operating system file descriptor associated + with the LPC socket. "State" is the current operational state of the LPC + socket. "Mode" is the socket mode, which is passed as an argument to + socket_create(). The local and remote addresses are the Internet address + and port numbers in Internet dot notations. '*' indicates an address or + which is 0. N.B. LPC sockets that are in the CLOSED state are not + currently in use; therefore the data displayed for that socket may be + idiosyncratic. + + The following output was generated on Portals, where the only socket + application running at the time was MWHOD. It indicates that two + sockets are current in use, one is listening for connection requests + on a STREAM mode socket. The other is waiting for incoming data on + a DATAGRAM mode socket. + + <pre> + Fd State Mode Local Address Remote Address + -- --------- -------- ----------------- ------------------ + 13 LISTEN STREAM *.6889 *.* + 14 BOUND DATAGRAM *.6888 *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + -1 CLOSED MUD *.* *.* + </pre> + + See also: + debug_info, + dump_file_descriptors + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/dumpallobj ds2.1/lib/doc/efun/internals/dumpallobj *** ds1.1/lib/doc/efun/internals/dumpallobj Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/dumpallobj Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + dumpallobj - report various statistics on all objects that have been loaded + + void dumpallobj(); + + void dumpallobj( string ); + + This function dumps a list of statistics on all objects that have been loaded. + If no argument is specified, then the information will be dumped to a file + named /OBJ_DUMP. If an argument is specified, then that name is used as + the filename for the dump. + + See also: + mud_status, + debug_info + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/get_config ds2.1/lib/doc/efun/internals/get_config *** ds1.1/lib/doc/efun/internals/get_config Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/get_config Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + get_config - query various driver config settings + + mixed get_config( int ); + + This efun is used to query the driver's various config + settings. Please refer to the "runtime_config.h" + include file for a list of currently recognized options. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/index ds2.1/lib/doc/efun/internals/index *** ds1.1/lib/doc/efun/internals/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,31 ---- + Internal efuns + + Efuns which give internal information about the driver process, or assist + with debugging the driver itself. + + <DL> + * cache_stats + * debug_info + * debugmalloc + * dump_file_descriptors + * dump_prog + * dump_socket_status + * dumpallobj + * get_config + * malloc_status + * memory_info + * mud_status + * opcprof + * query_load_average + * refs + * rusage + * set_debug_level + * set_malloc_mask + * swap + * time_expression + * trace + * traceprefix + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/internals/malloc_status ds2.1/lib/doc/efun/internals/malloc_status *** ds1.1/lib/doc/efun/internals/malloc_status Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/malloc_status Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + malloc_status - report various statistics related to memory usage. + + string malloc_status(); + + This function returns memory usage statistics in a string. + This function replaces the hardcoded 'malloc' command in vanilla 3.1.2. + Note that the output produced by malloc_status() depends upon which + memory management package is chosen in options.h when building the driver. + + See also: + mud_status, + dumpallobj, + memory_info + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/internals/memory_info ds2.1/lib/doc/efun/internals/memory_info *** ds1.1/lib/doc/efun/internals/memory_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/memory_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + memory_info - obtain info on object/overall memory usage + + varargs int memory_info( object ob ); + + If optional argument `ob' is given, memory_info() returns the approximate + amount of memory that `ob' is using. If no argument is given, memory_info() + returns the approximate amount of memory that the entire mud is using. Note + that the amount of memory the mud is using does not necessarily correspond + to the amount of memory actually allocated by the mud from the system, and + that total memory used by all the objects is not additive due to sharing of + certain structures. + + See also: + debug_info, + malloc_status, + mud_status + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/mud_status ds2.1/lib/doc/efun/internals/mud_status *** ds1.1/lib/doc/efun/internals/mud_status Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/mud_status Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + mud_status - report various driver and mudlib statistics + + string mud_status( int extra ); + + This function returns a string containing driver and mudlib statistics. + If extra is non-zero, then additional information about various internal + tables is included as well. This efun replaces the hardcoded 'status' + and 'status tables' commands in vanilla 3.1.2. + + See also: + debug_info, + dumpallobj, + memory_info, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/opcprof ds2.1/lib/doc/efun/internals/opcprof *** ds1.1/lib/doc/efun/internals/opcprof Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/opcprof Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + opcprof - reports statistics on calling frequencies of various efuns + + void opcprof(); + + void opcprof( string ); + + This function dumps a list of statistics on each efunction and eoperator. + If no argument is specified, then the information will be dumped to files + named /OPCPROF.efun and /OPCPROF.eoper. If an argument is specified, then + that name is used as the filename for the dump. + + See also: + function_profile + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/query_load_average ds2.1/lib/doc/efun/internals/query_load_average *** ds1.1/lib/doc/efun/internals/query_load_average Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/query_load_average Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + query_load_average - forces an error to occur in an object + + string query_load_average(); + + This function returns a string which reports two things: 1) user commands + per second, and 2) compiled lines per second. + + See also: + rusage + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/refs ds2.1/lib/doc/efun/internals/refs *** ds1.1/lib/doc/efun/internals/refs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/refs Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + refs - return the number of references to a data structure + + int refs( mixed data ); + + This efun is only available if PACKAGE_DEVELOP is compiled in. + + The number of references to `data' will be returned by refs(). This is + useful for deciding whether or not to make a copy of a data structure + before returning it. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/rusage ds2.1/lib/doc/efun/internals/rusage *** ds1.1/lib/doc/efun/internals/rusage Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/rusage Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,35 ---- + rusage - reports information gathered by the getrusage() system call + + mapping rusage(); + + This efun collects information gathered via the getrusage() system + call. Read the getrusage() man page for more information on what information + will be collected. Some systems do not have the getrusage() system call + but do have the times() system call. On those systems, only "utime" + and "stime" will be available. Times are reported in milliseconds. + + Here is an example usage of rusage(): + + <pre> + void + create() + { + mapping info; + + info = rusage(); + write("user time = " + info["utime"] + "ms\\n"); + write("system time = " + info["stime"] + "ms\\n"); + } + </pre> + + The available fields are: + utime, stime, maxrss, ixrss, idrss, isrss, minflt, majflt, nswap, inblock, + oublock, msgsnd, msgrcv, nsignals, nvcsw, nivcsw. + + See also: + time_expression, + function_profile, + time, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/set_debug_level ds2.1/lib/doc/efun/internals/set_debug_level *** ds1.1/lib/doc/efun/internals/set_debug_level Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/set_debug_level Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + set_debug_level - sets the debug level used by the driver's debug() macro + + void set_debug_level( int level ); + + This efun is only available when the driver is compiled with -DDEBUG_MACRO. + The purpose of this efun is to allow the amount and type of debugging + information produced to be controlled from within the mud (while the + driver is running). + + For more information, read the file debug.h which is included with the + driver source. + + See also: + set_malloc_mask + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/set_malloc_mask ds2.1/lib/doc/efun/internals/set_malloc_mask *** ds1.1/lib/doc/efun/internals/set_malloc_mask Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/set_malloc_mask Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + set_malloc_mask - sets the mask controlling display of malloc debug info + + void set_malloc_mask( int mask ); + + This efun is only available when PACKAGE_DEVELOP, DEBUGMALLOC and DEBUGMALLOC_EXTENSIONS are + both defined in options.h at driver build time. The mask controls what + memory-related debugging information is displayed as the driver allocates + and deallocates memory. Read md.c in the driver source for more information. + + See also: + debugmalloc + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/swap ds2.1/lib/doc/efun/internals/swap *** ds1.1/lib/doc/efun/internals/swap Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/swap Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + swap - swap out a file explicitly + + void swap( object ); + + This efun is only available if the driver is compiled with -DDEBUG. + + This efun should be reserved for debugging only. It + allows an object to be explicitly swapped out. If + enabled, it is strongly recommended that a simul_efun + override (for this efun) be used to prevent abuse. + + Note: objects which have been destructed, already + swapped out, contain a heart beat, cloned, inherited, + or interactive, cannot be swapped out. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/time_expression ds2.1/lib/doc/efun/internals/time_expression *** ds1.1/lib/doc/efun/internals/time_expression Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/time_expression Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + time_expression - return the amount of real time that an expression took + + int time_expression( mixed expr ); + + int time_expression { ... } + + Evaluate <expr> or the specified block of code. The amount of real time + that passes during the evaluation of <expr>, in microseconds, is returned. + The precision of the value is + not necessarily 1 microsecond; in fact, it probably is much less precise. + + See also: + rusage, + function_profile, + time + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/internals/trace ds2.1/lib/doc/efun/internals/trace *** ds1.1/lib/doc/efun/internals/trace Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/trace Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,25 ---- + trace - sets trace flags and returns the old ones + + int trace( int traceflags ); + + This efun is only available if TRACE and PACKAGE_DEVELOP are compiled in. + + Sets the trace flags and returns the old trace flags. + When tracing is on a lot of information is printed during execution. + + The trace bits are: + <DL> + * 1 - Trace all function calls to lfuns. + * 2 - Trace all calls to "call_other". + * 4 - Trace all function returns. + * 8 - Print arguments at function calls and return values. + * 16 - Print all executed stack machine instructions (produces a lot of output!). + * 32 - Enable trace in heart beat functions. + * 64 - Trace calls to apply. + * 128 - Show object name in tracing. + </DL> + + See also: + traceprefix + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/internals/traceprefix ds2.1/lib/doc/efun/internals/traceprefix *** ds1.1/lib/doc/efun/internals/traceprefix Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/internals/traceprefix Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + traceprefix - sets the prefix determining which objects to trace + + string traceprefix( string prefix ); + + This efun is only available if TRACE and PACKAGE_DEVELOP are compiled in. + + If the the traceprefix is set (i.e. not 0) tracing will only occur in objects + having a name with the set prefix. + + The old value is returned. + + See also: + trace + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/mappings/allocate_mapping ds2.1/lib/doc/efun/mappings/allocate_mapping *** ds1.1/lib/doc/efun/mappings/allocate_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/allocate_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + allocate_mapping - pre-allocate space for a mapping + + mapping allocate_mapping( int size ); + + Returns a mapping with space for 'size' elements preallocated. + + For example: + + <pre> + mapping x; + int y = 200; + + x = allocate_mapping(y); + </pre> + + where y is the initial size of the mapping. Using allocate_mapping is + the preferred way to initalize the mapping if you have some idea of how + many elements the map will contain (200 in this case). The reason is that + allocating storage all at once is slightly more efficient. Thus if + you are using mappings to store a soul with 200 entries, the above + initialization would be quite appropriate. Note, that the + above initialization does not restrict you to 200 entries. + + See also: + map_delete + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/filter_mapping ds2.1/lib/doc/efun/mappings/filter_mapping *** ds1.1/lib/doc/efun/mappings/filter_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/filter_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + filter_mapping - return a selective sub-mapping + + mapping filter_mapping(mapping map, string fun, object ob, mixed extra, ...); + + mapping filter_array(mapping map, function f, mixed extra, ...); + + filter_mapping() is really the same as the filter() efun. + + See also: + filter + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/index ds2.1/lib/doc/efun/mappings/index *** ds1.1/lib/doc/efun/mappings/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + Mapping Efuns + + The following efuns operate on mappings: + + <DL> + * allocate_mapping + * keys + * map_delete + * map_mapping + * mapp + * match_path + * unique_mapping + * values + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/keys ds2.1/lib/doc/efun/mappings/keys *** ds1.1/lib/doc/efun/mappings/keys Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/keys Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + keys - return an array of the keys from the (key, value) pairs in a mapping + + array keys( mapping m ); + + keys() returns an array of keys (indices) corresponding to the keys in + the (key, value) pairs stored in the mapping m. + + For example, if: + + <pre> + mapping m; + m = (["hp" : 35, "sp" : 42, "mass" : 100]); + </pre> + + then + + <pre> + keys(m) == ({"hp", "sp", "mass"}) + </pre> + + Note: the keys will not be returned in any apparent order. However, they + will be returned in the same order as the corresponding values (returned + by the values() efun). + + See also: + values + diff -c -r --new-file ds1.1/lib/doc/efun/mappings/m_delete ds2.1/lib/doc/efun/mappings/m_delete *** ds1.1/lib/doc/efun/mappings/m_delete Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/m_delete Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,28 ---- + m_delete - remove a key from a mapping + + mapping m_delete(mapping m, mixed element); + + This efun is only available if COMPAT_32 is defined. + + It behaves exactly like map_delete(), except that it returns its first + argument. + + Note: the 3.2 version actually returns a copy of the mapping, + so for strict compatibility the following simul is suggested: + + <pre> + mapping m_delete(mapping m, mixed element) + { + mapping ret = copy(m); + map_delete(ret, element); + return ret; + } + </pre> + + However, this version is significantly faster as it avoids the copy. + + See also: + map_delete + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/mappings/m_indices ds2.1/lib/doc/efun/mappings/m_indices *** ds1.1/lib/doc/efun/mappings/m_indices Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/m_indices Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + m_indices - return the keys of a mapping + + array m_indices(mapping); + + This efun is only available if COMPAT_32 is defined. It behaves exactly + the same as keys(). + + See also: + keys + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/m_values ds2.1/lib/doc/efun/mappings/m_values *** ds1.1/lib/doc/efun/mappings/m_values Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/m_values Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + m_values - return the values of a mapping + + array m_values(mapping); + + This efun is only available if COMPAT_32 is defined. It behaves exactly + the same as values(). + + See also: + values + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/map_delete ds2.1/lib/doc/efun/mappings/map_delete *** ds1.1/lib/doc/efun/mappings/map_delete Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/map_delete Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,34 ---- + map_delete - remove a (key, value) pair from a mapping based on the key + + void map_delete( mapping m, mixed element ); + + map_delete removes the (key, value) from the mapping m that has key equal + to element. + + For example, given: + + <pre> + mapping names; + + names = ([]); + names["truilkan"] = "john"; + names["wayfarer"] = "erik"; + names["jacques"] = "dwayne"; + </pre> + + Then: + <pre> + map_delete(names,"truilkan"); + </pre> + + causes the mapping 'names' to be equal to: + <pre> + (["wayfarer" : "erik", "jacques" : "dwayne"]) + </pre> + keys(names) will not contain "truilkan" after map_delete(names,"truilkan") + is called [unless ("truilkan", *) is subsequently added back to the mapping]. + + See also: + allocate_mapping + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/map_mapping ds2.1/lib/doc/efun/mappings/map_mapping *** ds1.1/lib/doc/efun/mappings/map_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/map_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + map_mapping - modify an mapping of elements via application of a function + + mapping map_mapping( mapping map, string fun, object ob, ... ); + + mapping map_mapping( mapping map, function f, ... ); + + Returns an mapping with the same keys as map whose items have been + mapped throught 'ob->fun()' or 'f'. The function is called for each + (key, value) pair in 'map' and the returned mapping has the return value + of the function as its value for each key. + The extra arguments are passed as parameters to the function + after the key and the value. + + See also: + filter_array, + filter, + sort_array, + map_array, + map + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/match_path ds2.1/lib/doc/efun/mappings/match_path *** ds1.1/lib/doc/efun/mappings/match_path Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/match_path Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + match_path - search a mapping for a path + + mixed match_path( mapping m, string str ); + + match_path() searches a mapping for a path. Each key is assumed to be a + string. The value is completely arbitrary. The efun finds the largest + matching path in the mapping. Keys ended in '/' are assumed to match paths + with character that follow the '/', i.e. / is a wildcard for anything below + this directory. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/unique_mapping ds2.1/lib/doc/efun/mappings/unique_mapping *** ds1.1/lib/doc/efun/mappings/unique_mapping Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/unique_mapping Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + unique_mapping - partition an array into groups + + mapping unique_mapping(array arr, string fun, object ob, ...); + + mapping unique_mapping(array arr, function f, ...); + + unique_mapping() evaluates the function 'f' with each element of the + array 'arr', and constructs a mapping with the return values as keys, + and subarrays of elements that returned value value as values. + + See also: + unique_array + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mappings/values ds2.1/lib/doc/efun/mappings/values *** ds1.1/lib/doc/efun/mappings/values Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mappings/values Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,26 ---- + values - return an array of the values from the (key, value) pairs in a mapping + + array values( mapping m ); + + values() returns an array of values corresponding to the value elements + in the (key, value) pairs stored in the mapping m. + + For example, if: + + <pre> + mapping m; + + m = (["hp" : 35, "sp" : 42, "mass" : 100]); + </pre> + + then + + <pre> + values(m) == ({35, 42, 100}) + </pre> + + Note: the values will be returned in the same order as the corresponding + keys. + + See also: + keys diff -c -r --new-file ds1.1/lib/doc/efun/mixed/arrayp ds2.1/lib/doc/efun/mixed/arrayp *** ds1.1/lib/doc/efun/mixed/arrayp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/arrayp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + arrayp - determine whether or not a given variable is an array + + int arrayp( mixed arg ); + + Return 1 if `arg' is an array, zero otherwise. + + See also: + typeof diff -c -r --new-file ds1.1/lib/doc/efun/mixed/bufferp ds2.1/lib/doc/efun/mixed/bufferp *** ds1.1/lib/doc/efun/mixed/bufferp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/bufferp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + bufferp - determine whether or not a given variable is a buffer + + int bufferp( mixed arg ); + + Return 1 if `arg' is a buffer value and zero otherwise. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/classp ds2.1/lib/doc/efun/mixed/classp *** ds1.1/lib/doc/efun/mixed/classp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/classp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + classp - determine whether or not a given variable is a class + + int classp(mixed); + + Return 1 if the argument is a class. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/floatp ds2.1/lib/doc/efun/mixed/floatp *** ds1.1/lib/doc/efun/mixed/floatp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/floatp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + floatp - determine whether or not a given variable is a float + + int floatp( mixed arg ); + + Return 1 if `arg' is a float number and zero (0) otherwise. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/functionp ds2.1/lib/doc/efun/mixed/functionp *** ds1.1/lib/doc/efun/mixed/functionp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/functionp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,49 ---- + functionp - determine whether or not a given variable is a function + pointer + + int functionp( mixed arg ); + + Return nonzero if `arg' is a function pointer and zero (0) otherwise. + Function pointers are variables of type 'function' as indicated in the + documentation for the type 'function', for example: + + f = (: call_other, obj, func :); + + The return value indicates the type of function pointer using the + values given in the driver include file "include/function.h". + + <DL> + * FP_LOCAL - lfun pointer + * FP_EFUN - efun pointer + * FP_SIMUL - simul pointer + * FP_FUNCTIONAL - functional + </DL> + + These values are bit values; the following flags may be added as well: + + <DL> + * FP_HAS_ARGUMENTS - arguments were included in the definition + * FP_OWNER_DESTED - the owner of this function pointer has been destructed + * FP_NOT_BINDABLE - it isn't possible to rebind this function pointer + </DL> + + To test if a function variable is an efun pointer: + + if (functionp(f) & FP_EFUN) ... + + to test if it is an efun or simul_efun: + + if (functionp(f) & (FP_EFUN | FP_SIMUL)) ... + + Try (very hard) to call the function: + + <pre> + if (functionp(f) & FP_OWNER_DESTED) { + if (functionp(f) & FP_NOT_BINDABLE) + error("Function could not be rebound.\n"); + f = bind(f, this_object()); + } + evaluate(f); + </pre> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/intp ds2.1/lib/doc/efun/mixed/intp *** ds1.1/lib/doc/efun/mixed/intp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/intp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + intp - determine whether or not a given variable is an integer + + int intp( mixed arg ); + + Return 1 if 'arg' is an integer number and zero (0) otherwise. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/mapp ds2.1/lib/doc/efun/mixed/mapp *** ds1.1/lib/doc/efun/mixed/mapp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/mapp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + mapp - determine whether or not a given variable is a mapping + + int mapp( mixed arg ); + + Return 1 if `arg' is a mapping. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/nullp ds2.1/lib/doc/efun/mixed/nullp *** ds1.1/lib/doc/efun/mixed/nullp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/nullp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + nullp - determine whether or not a given variable is null + + int nullp( mixed arg ); + + Exactly the same as undefinedp(). Exists for compatibility. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/objectp ds2.1/lib/doc/efun/mixed/objectp *** ds1.1/lib/doc/efun/mixed/objectp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/objectp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + objectp - determine whether or not a given variable is an object + + int objectp( mixed arg ); + + Return 1 if `arg' is an object. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/pointerp ds2.1/lib/doc/efun/mixed/pointerp *** ds1.1/lib/doc/efun/mixed/pointerp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/pointerp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + pointerp - determine whether or not a given variable is an array + + int pointerp( mixed arg ); + + pointerp() is provided for compatibility; it is the same as the arrayp() efun. + + See also: + arrayp diff -c -r --new-file ds1.1/lib/doc/efun/mixed/stringp ds2.1/lib/doc/efun/mixed/stringp *** ds1.1/lib/doc/efun/mixed/stringp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/stringp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + stringp - determine whether or not a given variable is a string + + int stringp( mixed arg ); + + Returns 1 if 'arg' is a string, and zero if not. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mixed/undefinedp ds2.1/lib/doc/efun/mixed/undefinedp *** ds1.1/lib/doc/efun/mixed/undefinedp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mixed/undefinedp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + undefinedp - determine whether or not a given value is undefined. + + int undefinedp( mixed arg ); + + Return 1 if `arg' is undefined. 'arg' will be undefined in the following + cases: + + <DL> + * it is a variable set equal to the return value of a call_other to a + non-existent method (e.g. arg = call_other(obj, "???")). + * it is a variable set equal to the return value of an access of an + element in a mapping that doesn't exist (e.g. arg = map[not_there]). + * it has not yet been initialized. + * it points to a destructed object. + * it is a function (formal) parameter that corresponds to a missing actual argument. + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/author_stats ds2.1/lib/doc/efun/mudlib/author_stats *** ds1.1/lib/doc/efun/mudlib/author_stats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/author_stats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,43 ---- + author_stats - returns statistics gathered on authors + + mapping author_stats( string domain); + + This efun is only avaiable if PACKAGE_MUDLIB_STATS is compiled in. + + Both domain_stats() and author_stats() return information stored in a + mapping. If no argument is specified, then information is returned on + all domains (or on all authors) with one map entry per domain or author. + If an argument is specified, then a map is returned that corresponds to + that domain or author with keys: moves, cost, errors, heart_beats, + array_size, and objects. Each of these map to integer values. + Moves is the number of objects that have moved into objects in the + given domain. Cost is the number of evaluations (eval_cost) accumulated + by objects with the given domain (or author). Errors is the number of errors + incurred by objects with the given domain. Heart_beats is the number of + heartbeat calls made on objects having the given domain. + Array_size is the size (in bytes) of the arrays allocated by the domain. + Objects is the number of objects created by the given domain. When called + with no arguments, the returned mapping has a form like this: + + <pre> + ([ domain0 : info0, domain1 : info1, ... ]) + </pre> + + while info0 has the form: + + <pre> + ([ "moves" : moves, "cost" : cost, "errors" : errors, + "heart_beats" : heart_beats, "worth" : worth, + "array_size" : array_size, "objects" : objects ]) + </pre> + + When called with an argument, the returned mapping will have the form of + info0. + + See also: + domain_file, + author_file, + set_author + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/domain_stats ds2.1/lib/doc/efun/mudlib/domain_stats *** ds1.1/lib/doc/efun/mudlib/domain_stats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/domain_stats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,42 ---- + domain_stats - returns statistics gathered on domains + + mapping domain_stats( string domain ); + + This efun is only available if PACKAGE_MUDLIB_STATS is compiled into the driver. + + Both domain_stats() and author_stats() return information stored in a + mapping. If no argument is specified, then information is returned on + all domains (or on all authors) with one map entry per domain or author. + If an argument is specified, then a map is returned that corresponds to + that domain or author with keys: moves, cost, errors, heart_beats, + array_size, and objects. Each of these map to integer values. + Moves is the number of objects that have moved into objects in the + given domain. Cost is the number of evaluations (eval_cost) accumulated + by objects with the given domain (or author). Errors is the number of errors + incurred by objects with the given domain. Heart_beats is the number of + heartbeat calls made on objects having the given domain. + Array_size is the size (in bytes) of the arrays allocated by the domain. + Objects is the number of objects created by the given domain. When called + with no arguments, the returned mapping has a form like this: + + <pre> + ([ domain0 : info0, domain1 : info1, ... ]) + </pre> + + while info0 has the form: + + <pre> + ([ "moves" : moves, "cost" : cost, "errors" : errors, + "heart_beats" : heart_beats, "worth" : worth, + "array_size" : array_size, "objects" : objects ]) + </pre> + + When called with an argument, the returned mapping will have the form of + info0. + + See also: + domain_file, + author_file, + set_author + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/export_uid ds2.1/lib/doc/efun/mudlib/export_uid *** ds1.1/lib/doc/efun/mudlib/export_uid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/export_uid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + export_uid - set the uid of another object + + int export_uid( object ob ); + + This efun is only available if PACKAGE_UIDS is compiled in. + + Set the uid of 'ob' to the effective uid of this_object(). It is + only possible when 'ob' has an effective uid of 0. + + See also: + seteuid, + getuid, + geteuid, + valid_seteuid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/find_living ds2.1/lib/doc/efun/mudlib/find_living *** ds1.1/lib/doc/efun/mudlib/find_living Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/find_living Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + find_living - find a living object matching a given id + + object find_living( string str ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Find first the object that is marked as living, and answers to the + id 'str'. A living object is an object that has called + enable_commands(). The object must have set a name with + set_living_name(), so its name will be entered into the hash table + used to speed up the search for living objects. + + See also: + living, + livings, + users, + disable_commands, + enable_commands, + set_living_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/geteuid ds2.1/lib/doc/efun/mudlib/geteuid *** ds1.1/lib/doc/efun/mudlib/geteuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/geteuid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + geteuid - return the effective user id of an object or function + + string geteuid( object|function ); + + This efun is only available if PACKAGE_UIDS is compiled into the driver. + + If given an object argument, geteuid returns the effective user id (euid) + of the object. If given an argument of type 'function', it returns the + euid of the object that created that 'function' variable. If the object, + at the time of the function variable's construction, had no euid, the + object's uid is stored instead. + + See also: + seteuid, + getuid, + export_uid, + valid_seteuid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/getuid ds2.1/lib/doc/efun/mudlib/getuid *** ds1.1/lib/doc/efun/mudlib/getuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/getuid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + getuid - return the user id (uid) of an object + + string getuid( object ob ); + + This efun is only available if PACKAGE_UIDS is compiled into the driver. + + Returns the user id of an object. The uid of an object is determined at + object creation by the creator_file() function. + + See also: + seteuid, + geteuid, + export_uid, + valid_seteuid, + creator_file + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/index ds2.1/lib/doc/efun/mudlib/index *** ds1.1/lib/doc/efun/mudlib/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + Mudlib related efuns + + These efuns do things which probably should be done by the mudlib, but + are kept for backwards compatibility. + + <DL> + * author_stats + * domain_stats + * export_uid + * find_living + * geteuid + * getuid + * living + * livings + * query_privs + * set_author + * set_light + * set_living_name + * set_privs + * seteuid + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/living ds2.1/lib/doc/efun/mudlib/living *** ds1.1/lib/doc/efun/mudlib/living Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/living Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + living - detects whether or not a given object is "living" + + int living( object ob ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Return true if `ob' is a living object (that is, if "enable_commands()" has + been called by `ob'). + + See also: + enable_commands + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/livings ds2.1/lib/doc/efun/mudlib/livings *** ds1.1/lib/doc/efun/mudlib/livings Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/livings Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + livings - return an array of all living objects + + object array livings(); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Returns an array of pointers to all living objects (objects that have + had enable_commands() called in them). + + See also: + enable_commands, + find_living, + users + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/query_privs ds2.1/lib/doc/efun/mudlib/query_privs *** ds1.1/lib/doc/efun/mudlib/query_privs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/query_privs Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + query_privs - return the privs string for an object + + string query_privs( object ob ); + + Returns the privs string for an object. The privs string is determined + at compile time via a call to privs_file() in the master object, and changeable + via the set_privs() efun. + + This efun is only available if PRIVS is defined at driver compile time. + + See also: + privs_file, + set_privs + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/set_author ds2.1/lib/doc/efun/mudlib/set_author *** ds1.1/lib/doc/efun/mudlib/set_author Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/set_author Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + set_author - set the author associated with an object + + void set_author( string author ); + + Every object has both an author and a domain associated with it for + the purposes of tracking statistics for authors and domains. Domains + may only be set in the master object function domain_file(), however + authors are different. They can be initialized to some default value + by author_file() in the master object, but can also be changed using + the set_author efun. + + set_author changes the author of the object that it is called within. + That author will get credit for all future actions of that object that + affect mudlib statistics. + + See also: + author_file, + domain_file, + author_stats, + set_author, + domain_stats + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/set_light ds2.1/lib/doc/efun/mudlib/set_light *** ds1.1/lib/doc/efun/mudlib/set_light Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/set_light Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + set_light - update or query an object's light level + + int set_light( int light_level_adjustment ); + + This efun is only available if NO_LIGHT is not compiled in. + + Passing 'light_level_adjustment' as 0 queries the object's current + light level. A positive number will increase the light level, while + a negative number will decrease the light level. + + Note that the object's current light level includes the light it sees from + other objects. + + This efun is provided mostly for backwards compatibility; it really should + be handled by the mudlib. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/set_living_name ds2.1/lib/doc/efun/mudlib/set_living_name *** ds1.1/lib/doc/efun/mudlib/set_living_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/set_living_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_living_name - set a living name for a living object + + void set_living_name( string name ); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Set a living name on an object that is living. After this has been done, the + object can be found with "find_living()". + + See also: + enable_commands, + find_living, + find_player + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/set_privs ds2.1/lib/doc/efun/mudlib/set_privs *** ds1.1/lib/doc/efun/mudlib/set_privs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/set_privs Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_privs - set the privs string for an object + + void set_privs( object ob, string privs ); + + This efun is only available when PRIVS is compiled in. + + Sets the privs string for 'ob' to 'privs'. + + This efun is only available if PRIVS is defined at driver compile time. + + See also: + privs_file, + query_privs + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/mudlib/seteuid ds2.1/lib/doc/efun/mudlib/seteuid *** ds1.1/lib/doc/efun/mudlib/seteuid Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/mudlib/seteuid Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + seteuid - set the effective user id (euid) of an object + + int seteuid( string str ); + + This efun is only available if PACKAGE_UIDS is compiled in. + + Set effective uid to 'str'. valid_seteuid() in master.c controls which + values the euid of an object may be set to. + + When this value is 0, then the current object's uid can be changed by + export_uid(), and only then. + + But, when the value is 0, no objects can be loaded or cloned by this object. + + See also: + export_uid, + getuid, + geteuid, + valid_seteuid + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/numbers/index ds2.1/lib/doc/efun/numbers/index *** ds1.1/lib/doc/efun/numbers/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/numbers/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + Efuns relating to ints + + Pretty trivial stuff here + + <DL> + * intp + * nullp + * random + * to_float + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/numbers/random ds2.1/lib/doc/efun/numbers/random *** ds1.1/lib/doc/efun/numbers/random Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/numbers/random Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,7 ---- + random - return a pseudo-random number + + int random( int n ); + + Return a pseudo-random number from the range [0 .. (n -1)] (inclusive). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/numbers/to_float ds2.1/lib/doc/efun/numbers/to_float *** ds1.1/lib/doc/efun/numbers/to_float Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/numbers/to_float Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + to_float - convert an int to a float + + float to_float( int i ); + + The to_float() call returns the number of type 'float' that is equivalent to + the int 'i'. + + See also: + to_int, + read_buffer, + sprintf, + sscanf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/objects/all_inventory ds2.1/lib/doc/efun/objects/all_inventory *** ds1.1/lib/doc/efun/objects/all_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/all_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + all_inventory - return the inventory of an object + + object array all_inventory( object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled into the driver. + + Returns an array of the objects contained inside of 'ob'. If 'ob' is + omitted, this_object() is used. + + See also: + deep_inventory, + environment + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/children ds2.1/lib/doc/efun/objects/children *** ds1.1/lib/doc/efun/objects/children Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/children Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + children - returns an array of objects cloned from a given file + + object array children( string name ); + + This efun returns an array of objects that have been loaded or cloned from + the file named by 'name' (including the object 'name' itself, if loaded). + + See also: + deep_inherit_list, + inherit_list, + objects + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/clone_object ds2.1/lib/doc/efun/objects/clone_object *** ds1.1/lib/doc/efun/objects/clone_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/clone_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + clone_object - load a copy of an object + + object clone_object( string name, ... ); + + object new( string name, ... ); + + Create a new object from the file 'name', and give it a new unique + name (by adding #xxx on to the end of the name). Returns the new object. + The object shares the program of the object 'name', but has its own + set of variables. The second and following arguments are passed to + create() + + See also: + destruct, + move_object, + new + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/clonep ds2.1/lib/doc/efun/objects/clonep *** ds1.1/lib/doc/efun/objects/clonep Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/clonep Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + clonep - determine whether or not a given variable points to a cloned object + + int clonep(); + + int clonep(mixed arg); + + Returns true (1) iff the argument is objectp() and the O_CLONE flag is set. + The driver sets the O_CLONE flag for those objects created via new() + (clone_object()). The clonep() efun will not return true when called on + objects that are the blueprint copy (those that are loaded via call_other() + or load_object()). + + Note that if clonep() returns true, then file_name() will return a string + containing a '#'. clonep() defaults to this_object(). + + See also: + objectp, + new, + clone_object, + call_other, + file_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/objects/deep_inventory ds2.1/lib/doc/efun/objects/deep_inventory *** ds1.1/lib/doc/efun/objects/deep_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/deep_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + deep_inventory - return the nested inventory of an object + + object array deep_inventory( object ob ); + + This efun is only available when NO_ENVIRONMENT is not compiled into the + driver. + + Returns an array of the objects contained in the inventory of 'ob' and + also all the objects contained in the inventories of those objects and so on. + + See also: + all_inventory + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/destruct ds2.1/lib/doc/efun/objects/destruct *** ds1.1/lib/doc/efun/objects/destruct Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/destruct Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + destruct - remove an object + + void destruct( object ob ); + + Completely destroy and remove object 'ob'. After the call to destruct(). + If 'ob' is this_object(), execution will continue, but it is best to return + a value immediately. All pointers to the object in any variable or structure + will immediately become zero. move_or_destruct() is called in all the + objects inside of the object being destructed. + + See also: + clone_object, + new, + move_or_destruct + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/environment ds2.1/lib/doc/efun/objects/environment *** ds1.1/lib/doc/efun/objects/environment Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/environment Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + environment - return the environment of an object + + object environment( object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + Return the containing object (environment) of 'ob'. If no argument + is given, 'ob' defaults to this_object(). If the object is not + inside anything, zero is returned. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/file_name ds2.1/lib/doc/efun/objects/file_name *** ds1.1/lib/doc/efun/objects/file_name Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/file_name Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + file_name - get the file name of an object + + string file_name( object ob ); + + file_name() returns the name of the file from which 'ob' was loaded. + If the object is a cloned object, then file_name() will not be an + actual file on disk, but will be the name of the file from which the + object was originally cloned, appended with an octothorpe (#) and the + object instance number. Object instance numbers start at 0 when the + game is booted, and increase by one for each object cloned, hence the + number is unique for each cloned object. 'ob' defaults to this_object() + if not specified. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/find_object ds2.1/lib/doc/efun/objects/find_object *** ds1.1/lib/doc/efun/objects/find_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/find_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + find_object - find an object by file name + + object find_object( string str ); + + Find the object with the file name 'str'. If the object is a + cloned object, then it can be found using the file name which + would by returned if file_name() was called with it as the + argument. + + See also: + file_name + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/objects/first_inventory ds2.1/lib/doc/efun/objects/first_inventory *** ds1.1/lib/doc/efun/objects/first_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/first_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + first_inventory - return the first item in an object's inventory + + object first_inventory( mixed ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + Return the first object in the inventory of 'ob', where 'ob' is + either an object or the file name of an object. + + See also: + file_name, + next_inventory, + all_inventory, + deep_inventory + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/heart_beat_info ds2.1/lib/doc/efun/objects/heart_beat_info *** ds1.1/lib/doc/efun/objects/heart_beat_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/heart_beat_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + heart_beat_info - return an array of objects with active heartbeats + + object array heart_beat_info(); + + Returns an array of all the objects with active heart_beats. This efun + is only available if COMPAT_32 is defined. + + See also: + heart_beats.html + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/heart_beats ds2.1/lib/doc/efun/objects/heart_beats *** ds1.1/lib/doc/efun/objects/heart_beats Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/heart_beats Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + heart_beats - return an array of objects with active heartbeats + + object array heart_beats(); + + Returns an array of all the objects with active heart_beats. This efun + is only available if PACKAGE_CONTRIB is defined. + + See also: + heart_beat, + set_heart_beat, + query_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/index ds2.1/lib/doc/efun/objects/index *** ds1.1/lib/doc/efun/objects/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,51 ---- + Object efuns + + <H3>The efuns are for moving and managing objects:</H3> + + environment related efuns: (Not available with NO_ENVIRONMENT) + + <DL> + * all_inventory + * deep_inventory + * environment + * first_inventory + * move_object + * next_inventory + * present + </DL> + + loading and managing objects: + <DL> + * children + * clone_object + * clonep + * destruct + * file_name + * find_object + * load_object + * master + * new + * objectp + * objects + * reload_object + * restore_object + * save_object + * set_hide + * virtualp + </DL> + + heart_beat related efuns: + <DL> + * query_heart_beat + * set_heart_beat + * heart_beat_info + * heart_beats + </DL> + + message sending efuns: + <DL> + * tell_object + * tell_room + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/load_object ds2.1/lib/doc/efun/objects/load_object *** ds1.1/lib/doc/efun/objects/load_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/load_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + load_object - find or load an object by file name + + object load_object( string str ); + + Find the object with the file name 'str'. If the object is already + loaded, it is returned (just like find_object()). If the file exists + and the object hasn't been loaded yet, it is loaded first, then the + new object is returned. Otherwise zero is returned. An error is + thrown only if the object has compile errors. + + See also: + file_name, + find_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/master ds2.1/lib/doc/efun/objects/master *** ds1.1/lib/doc/efun/objects/master Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/master Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + master - returns the master object + + object master(); + + Returns a pointer to the master object. + + See also: + find_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/move_object ds2.1/lib/doc/efun/objects/move_object *** ds1.1/lib/doc/efun/objects/move_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/move_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + move_object - move current object to another environment + + void move_object( mixed dest ); + + Move the current object into the object `dest'. dest should either be + a filename or an object. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/new ds2.1/lib/doc/efun/objects/new *** ds1.1/lib/doc/efun/objects/new Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/new Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + new + + object x = new( string name, ...); + class foo x = new(class foo); + + If given a string, it behaves like clone object. If given a class type, + it creates a new instance of the class type. + + See also: + clone_object, + destruct, + move_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/next_inventory ds2.1/lib/doc/efun/objects/next_inventory *** ds1.1/lib/doc/efun/objects/next_inventory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/next_inventory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + next_inventory - return the next object in the same inventory + + object next_inventory( object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + Return the next object in the same inventory as 'ob'. + + See also: + first_inventory, + all_inventory, + deep_inventory + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/objects ds2.1/lib/doc/efun/objects/objects *** ds1.1/lib/doc/efun/objects/objects Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/objects Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,25 ---- + objects - return an array of all loaded objects + + object array objects(); + + object array objects( string func, object ob ); + + object array objects( function f); + + An array of every object loaded on the mud is returned by objects(). Note + that if the system's maximum array size is set too low, objects() will + truncate its array, in which case it might not be too useful. + + If the optional `func' and `ob' parameters are given, then ob->func() + is called with each loaded object as an argument. If the function returns + nonzero, then that object is returned by objects(), otherwise it isn't. + + If 'f' is given, it will be called on all the objects as above. For + example, objects( (: clonep :) ) returns a list of all the clones in + existence. + + See also: + livings, + users + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/present ds2.1/lib/doc/efun/objects/present *** ds1.1/lib/doc/efun/objects/present Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/present Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + present - find an object by id + + object present( mixed str); + + object present( mixed str, object ob ); + + This efun is only available if NO_ENVIRONMENT is not compiled in. + + If an object for which id(str) returns true exists, return it. + + `str' can also be an object, in 'str' is searched for, instead of calling + the function id(). + + If `ob' is given, then the search is done in the inventory of `ob', otherwise + the object is searched for in the inventory of the current object, and + in the inventory of the environment of the current object. + + See also: + move_object, + environment + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/query_heart_beat ds2.1/lib/doc/efun/objects/query_heart_beat *** ds1.1/lib/doc/efun/objects/query_heart_beat Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/query_heart_beat Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + query_heart_beat() - query the status of an object's heartbeat + + int query_heart_beat( object ); + + Returns the value with which set_heart_beat() has been called with on + 'object'. If object is not given, it defaults to the current object. If + the object has no heart beat, 0 will be returned. + + See also: + heart_beat, + set_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/reload_object ds2.1/lib/doc/efun/objects/reload_object *** ds1.1/lib/doc/efun/objects/reload_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/reload_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + reload_object - return an object to its just-loaded state + + void reload_object( object ob ); + + When reload_object() is called on `ob', all the driver-maintained properties + are re-initialized (heart_beat, call_outs, light, shadows, etc), all + variables are re-initialized, and create() is called. It has a similar + effect to destructing/reloading the object, however, no disk access or + parsing is performed. + + See also: + new, + clone_object, + destruct + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/restore_object ds2.1/lib/doc/efun/objects/restore_object *** ds1.1/lib/doc/efun/objects/restore_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/restore_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + restore_object - restore values of variables from a file into an object + + int restore_object( string name, int flag ); + + Restore values of variables for current object from file `name'. If the + optional second argument is 1, then all of the non-static variables are not + zeroed out prior to restore (normally, they are). + + In the case of an error, the affected variable will be left untouched + and an error given. + + See also: + save_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/save_object ds2.1/lib/doc/efun/objects/save_object *** ds1.1/lib/doc/efun/objects/save_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/save_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + save_object - save the values of variables in an object into a file + + int save_object( string name, int flag ); + + Save all values of non-static variables in this object in the file 'name'. + valid_write() in the master object determines whether this is allowed. + If the optional second argument is 1, then variables that are zero (0) are also + saved (normally, they aren't). Object variables and function pointers + always save as 0. save_object() returns 1 for success, 0 for failure. + + See also: + restore_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/set_heart_beat ds2.1/lib/doc/efun/objects/set_heart_beat *** ds1.1/lib/doc/efun/objects/set_heart_beat Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/set_heart_beat Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + set_heart_beat - enable or disable an object's heartbeat + + int set_heart_beat( int flag ); + + Passing 'flag' as 0 disables the object's heart beat. Passing a 'flag' of + 1 will cause heart_beat() to be called in the object once each heart beat + (a variable number defined by your local administrator, usually 2 seconds). + Passing a 'flag' of greater than 1 will usually set the number of heart beats + in between calls to heart_beat(), however your local administrator may have + the system configured to treat any 'flag' above 1 as 1. + + See also: + heart_beat, + query_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/set_hide ds2.1/lib/doc/efun/objects/set_hide *** ds1.1/lib/doc/efun/objects/set_hide Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/set_hide Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_hide - set the hide flag on a hidable object + + void set_hide( int flag ); + + Sets the hidden flag of an object to `flag', which should be 0 or 1 + (hide disable, or hide enable, respectively). Only objects for which + `master()->valid_hide(ob)' returns true may make themselves hidden. + When the object is hidden, only other hidable objects will be able to + find the object with find_object(), or multiple-object returning efuns such + as users(), children(), all_inventory(), etc. + + See also: + valid_hide + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/tell_object ds2.1/lib/doc/efun/objects/tell_object *** ds1.1/lib/doc/efun/objects/tell_object Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/tell_object Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + tell_object - send a message to an object + + void tell_object( object ob, string str ); + + Send a message 'str' to object 'ob'. If it is an interactive object (a player), + then the message will go to him, otherwise it will go to the local + function "catch_tell()". + + See also: + write, + shout, + say, + tell_room, + catch_tell + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/tell_room ds2.1/lib/doc/efun/objects/tell_room *** ds1.1/lib/doc/efun/objects/tell_room Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/tell_room Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + tell_room - send a message to all objects in a room + + void tell_room( mixed ob, string str, object array exclude ); + + Send a message 'str' to object all objects in the room 'ob'. 'ob' can also + be the filename of the room (string). If 'exclude' is specified, all + objects in the exclude array will not receive the message. + + See also: + write, + shout, + say, + tell_object, + catch_tell + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/objects/virtualp ds2.1/lib/doc/efun/objects/virtualp *** ds1.1/lib/doc/efun/objects/virtualp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/objects/virtualp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + virtualp - determine whether or not a given variable points to a virtual object + + int virtualp( object arg ); + + Returns true (1) if the argument is objectp() and the O_VIRTUAL flag is set. + The driver sets the O_VIRTUAL flag for those objects created via the + 'compile_object' function in the master object. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/parsing/TODO ds2.1/lib/doc/efun/parsing/TODO *** ds1.1/lib/doc/efun/parsing/TODO Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/parsing/TODO Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + query_ip_port(void|object) [PACKAGE_CONTRIB] + mixed query_notify_fail() [!NO_ADD_ACTION] [PACKAGE_CONTRIB] + int remove_interactive(object) [PACKAGE_CONTRIB] + int remove_shadow(object ob) [!NO_SHADOWS] [PACKAGE_CONTRIB] + int replaceable(object, void | string array) [PACKAGE_CONTRIB] + float array rotate_x(float array, float) [PACKAGE_MATRIX] + float array rotate_y(float array, float) [PACKAGE_MATRIX] + float array rotate_z(float array, float) [PACKAGE_MATRIX] + float array scale(float array, float) [PACKAGE_MATRIX] + void set_this_player(object | int) [NO_ADD_ACTION] + void store_variable(string, mixed) [PACKAGE_CONTRIB] + string terminal_colour(string, mapping) [PACKAGE_CONTRIB] + float array translate(float array, float, float, float) [PACKAGE_MATRIX] + mapping unique_mapping(array, string|function, ...) + string upper_case(string) [PACKAGE_CONTRIB] + string array variables(object, int default: 0); [PACKAGE_CONTRIB] diff -c -r --new-file ds1.1/lib/doc/efun/parsing/index ds2.1/lib/doc/efun/parsing/index *** ds1.1/lib/doc/efun/parsing/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/parsing/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,9 ---- + Parsing efuns + + <H3>Various string parsing efuns:</H3> + + <DL> + * query_verb + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/parsing/query_verb ds2.1/lib/doc/efun/parsing/query_verb *** ds1.1/lib/doc/efun/parsing/query_verb Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/parsing/query_verb Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + query_verb - return the name of the command currently being executed + + string query_verb(); + + This efun is only available if NO_ADD_ACTION is not compiled in. + + Give the name of the current command, or 0 if not executing from a command. + This function is useful when several commands (verbs) may cause the same + function to execute and it is necessary to determine which verb it was + that invoked the function. + + See also: + add_action + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/index ds2.1/lib/doc/efun/sockets/index *** ds1.1/lib/doc/efun/sockets/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + Socket efuns + + These efuns allow TCP and UDP sockets to be created, allowing the MUD to + create internet connections other than its login ports. + + <DL> + + * socket_accept + * socket_acquire + * socket_address + * socket_bind + * socket_close + * socket_connect + * socket_create + * socket_error + * socket_listen + * socket_release + * socket_write + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_accept ds2.1/lib/doc/efun/sockets/socket_accept *** ds1.1/lib/doc/efun/sockets/socket_accept Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_accept Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,74 ---- + socket_accept - accept a connection on a socket + + int socket_accept( int s, string | function read_callback, string | function write_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + The argument s is a socket that has been created with socket_create(), + bound to an address with socket_bind(), and is listening for connections + after a socket_listen(). socket_accept() extracts the first connection + on the queue of pending connections, creates a new socket with the same + properties of s and allocates a new file descriptor for the socket. If no + pending connections are present on the queue, socket_accept() returns an + error as described below. The accepted socket is used to read and write data + to and from the socket which connected to this one; it is not used to accept + more connections. The original socket s remains open for accepting further + connections. + + The argument read_callback is the function or name of a function + for the driver to call when the new socket (not the accepting socket) + receives data. + + The write callback should follow this format: + + <pre> + void read_callback(int fd) + </pre> + + Where fd is the socket which is ready to accept data. + + The argument write_callback is the name of a function for the driver to + call when the new socket (not the accepting socket) is ready to be + written to. The write callback should follow this format: + + <pre> + void write_callback(int fd) + </pre> + + Where fd is the socket which is ready to be written to. + + Note: The close_callback of the accepting socket (not the new socket) + is called if the new socket closes unexpectedly, i.e. not as the result + of a socket_close() call. The close callback should follow this format: + + <pre> + void close_callback(int fd) + </pre> + + Where fd is the socket which has closed. + + socket_accept() returns a non-negative descriptor for the accepted + socket on success. On failure, it returns a negative value. socket_error() + can be used on the return value to get a text description of the error. + + ERRORS - these definitions are in socket_err.h + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEMODENOTSUPP Socket mode not supported. + * EENOTLISTN Socket not listening. + * EEWOULDBLOCK Operation would block. + * EEINTR Interrupted system call. + * EEACCEPT Problem with accept. + * EENOSOCKS No more available efun sockets. + </DL> + + See also: + socket_bind, + socket_connect, + socket_create, + socket_listen + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_acquire ds2.1/lib/doc/efun/sockets/socket_acquire *** ds1.1/lib/doc/efun/sockets/socket_acquire Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_acquire Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,32 ---- + socket_acquire - assume ownership of a socket + + int socket_acquire( int socket, string | function read_callback, + string | function write_callback, + string | function close_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_acquire() is called to complete the handshake begun by socket_release() + for transferring ownership (and control) of a socket to a new object. + socket_release() calls the release callback function within the new owner + object to notify the object that it wishes to pass control of the socket + on. It is the responsibility of the new owner socket to decide whether + it wishes to accept the socket. It it does, then socket_acquire() is + called to complete the transfer. If not, then the callback simply returns + without completing the handshake. + + In the former case the handshake is completed and the new object + becomes the socket owner. The read, write and close callback function + parameters refer to functions within the new object. These are specified + so that the MudOS driver will know which functions to call within the new + object. Decling to acquire the socket will cause socket_release() to + return EESOCKNOTRLSD so the owner can perform appropriate clean-up. + EESOCKNOTRLSD is in "socket_err.h". + + socket_acquire() may only be called within the context of thr release + callback function and only with the socket specified. + + See also: + socket_release + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_address ds2.1/lib/doc/efun/sockets/socket_address *** ds1.1/lib/doc/efun/sockets/socket_address Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_address Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + socket_address - return the remote address for an efun socket + + string socket_address( int s | object ob ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_address() returns the remote address for an efun socket s, or for + an interactive object ob. + + The returned address is of the form: + + "127.0.0.1 23". + + socket_address() returns: + + a string format address on success. + + an empty string on failure. + + See also: + socket_connect, + socket_create, + resolve, + query_host_name, + query_ip_number + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_bind ds2.1/lib/doc/efun/sockets/socket_bind *** ds1.1/lib/doc/efun/sockets/socket_bind Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_bind Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,36 ---- + socket_bind - bind a name to a socket + + int socket_bind( int s, int port ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_bind() assigns a name to an unnamed socket. When a socket is + created with socket_create() it exists in a name space (address family) + but has no name assigned. socket_bind() requests that the port be assigned + to the socket s. + + socket_bind() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - These errors are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEISBOUND Socket is already bound. + * EEADDRINUSE Address already in use. + * EEBIND Problem with bind. + * EEGETSOCKNAME Problem with getsockname. + </DL> + + See also: + socket_connect. + socket_create, + socket_listen + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_close ds2.1/lib/doc/efun/sockets/socket_close *** ds1.1/lib/doc/efun/sockets/socket_close Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_close Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + socket_close - close a socket + + int socket_close( int s ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_close() closes socket s. This frees a socket efun slot for use. + + socket_close() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + </DL> + + See also: + socket_accept, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_connect ds2.1/lib/doc/efun/sockets/socket_connect *** ds1.1/lib/doc/efun/sockets/socket_connect Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_connect Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,63 ---- + socket_connect - initiate a connection on a socket + + int socket_connect( int s, string address, + string read_callback, + string write_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + The argument s is a socket. s must be either a STREAM mode or a MUD mode + socket. address is the address to which the socket will attempt to connect. + address is of the form: "127.0.0.1 23" + + The argument read_callback is the name of a function for the driver to + call when the socket gets data from its peer. The read callback should follow + this format: + + <pre> + void read_callback(int fd, mixed message) + </pre> + + Where fd is the socket which received the data, and message is the data + which was received. + + The argument write_callback is the name of a function for the driver to + call when the socket is ready to be written to. The write callback should + follow this format: + + <pre> + void write_callback(int fd) + </pre> + + Where fd is the socket which is ready to be written to. + + socket_connect() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEMODENOTSUPP Socket mode not supported. + * EEISLISTEN Socket is listening. + * EEISCONN Socket is already connected. + * EEBADADDR Problem with address format. + * EEINTR Interrupted system call. + * EEADDRINUSE Address already in use. + * EEALREADY Operation already in progress. + * EECONNREFUSED Connection refused. + * EECONNECT Problem with connect. + </DL> + + See also: + socket_accept, + socket_close, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_create ds2.1/lib/doc/efun/sockets/socket_create *** ds1.1/lib/doc/efun/sockets/socket_create Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_create Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,64 ---- + socket_create - create an efun socket + + int socket_create( int mode, string | function read_callback); + + int socket_create( int mode, string | function read_callback, string | function close_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_create() creates an efun socket. mode determines which type of + socket is created. Currently supported socket modes are: + + <DL> + * MUD for sending LPC data types using TCP protocol. + * STREAM for sending raw data using TCP protocol. + * DATAGRAM for using UDP protocol. + </DL> + + The argument read_callback is the name of a function for the driver to + call when the socket gets data from its peer. The read callback should follow + this format: + + <pre> + void read_callback(int fd, mixed message) + </pre> + + Where fd is the socket which received the data, and message is the data + which was received. + + The argument close_callback is the name of a function for the driver to + call if the socket closes unexpectedly, i.e. not as the result of a + socket_close() call. The close callback should follow this format: + + <pre> + void close_callback(int fd) + </pre> + + Where fd is the socket which has closed. + NOTE: close_callback is not used with DATAGRAM mode sockets. + + socket_create() returns: + + a non-negative descriptor on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEMODENOTSUPP Socket mode not supported. + * EESOCKET Problem creating socket. + * EESETSOCKOPT Problem with setsockopt. + * EENONBLOCK Problem setting non-blocking mode. + * EENOSOCKS No more available efun sockets. + * EESECURITY Security violation attempted. + + See also: + socket_accept, + socket_bind, + socket_close, + socket_connect, + socket_listen, + socket_write + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_error ds2.1/lib/doc/efun/sockets/socket_error *** ds1.1/lib/doc/efun/sockets/socket_error Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_error Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + socket_error - return a text description of a socket error + + string socket_error( int error ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_error() returns a string describing the error signified by error. + + socket_error() returns: + + a string describing the error on success. + + "socket_error: invalid error number" on bad input. + + See also: + socket_create, + socket_connect + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_listen ds2.1/lib/doc/efun/sockets/socket_listen *** ds1.1/lib/doc/efun/sockets/socket_listen Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_listen Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,45 ---- + socket_listen - listen for connections on a socket + + int socket_listen( int s, string listen_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + To accept connections, a socket is first created with socket_create(), + the socket is them put into listening mode with socket_listen(), and + the connections are accepted with socket_accept(). The socket_listen() call + applies only to sockets of type STREAM or MUD. + + The argument listen_callback is the name of a function for the driver to + call when a connection is requested on the listening socket. The listen + callback should follow this format: + + <pre> + void listen_callback(int fd) + </pre> + + Where fd is the listening socket. + + socket_listen() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EEMODENOTSUPP Socket mode not supported. + * EENOADDR Socket not bound to an address. + * EEISCONN Socket is already connected. + * EELISTEN Problem with listen. + </DL> + + See also: + socket_accept, + socket_connect, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_release ds2.1/lib/doc/efun/sockets/socket_release *** ds1.1/lib/doc/efun/sockets/socket_release Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_release Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,35 ---- + socket_release - release ownership of a socket to another object + + int socket_release( int socket, object ob, + string release_callback ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_release() is used to change ownership (and control) of a socket + to another object. It is useful in daemon objects (like inetd) which + handle connection set-up and then transfer a connected socket to another + object for further processing. + + Socket ownership transfer involves a handshake between the current owner + object and the socket to which the current owner wishes to transfer the + socket. The handshake is initiated when socket_release() is called. + socket_release() does appropriate security/integrity checking and then + calls the release_callback function in object ob. This function is used + to notify ob that socket ownership is being transferred to it. It is + then ob's responsibility to call socket_acquire() within the release + callback function. If socket_acquire() is called then the handshake is + complete and socket ownership has been successfully transferred to ob. + ob may decline to accept responsibility for the socket by not calling + socket_acquire(), in which case ownership does not change and the + current socket owner must decide how to respond to this. + + If the socket owner is successfully transfered then socket_release() + returns EESUCCESS. If ob does not accept ownership for the socket then + EESOCKNOTRLSD is returned (both in "socket_err.h"). Other errors can be returned based on + security violation, bad socket descriptor vbalues, etc. + + See also: + socket_acquire + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/sockets/socket_write ds2.1/lib/doc/efun/sockets/socket_write *** ds1.1/lib/doc/efun/sockets/socket_write Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/sockets/socket_write Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,42 ---- + socket_write - send a message from a socket + + int socket_write( int s, mixed message, + void | string address ); + + This efun is only available if PACKAGE_SOCKETS is compiled in. + + socket_write() sends a message on a socket s. If the socket s is of type + STREAM or MUD, the socket must already be connected and the address is not + specified. If the socket is of type DATAGRAM, the address must be specified. + The address is of the form: "127.0.0.1 23". + + socket_write() returns: + + EESUCCESS on success. + + a negative value indicated below on error. + + ERRORS - these are in "socket_err.h" + + <DL> + * EEFDRANGE Descriptor out of range. + * EEBADF Descriptor is invalid. + * EESECURITY Security violation attempted. + * EENOADDR Socket not bound to an address. + * EEBADADDR Problem with address format. + * EENOTCONN Socket not connected. + * EEALREADY Operation already in progress. + * EETYPENOTSUPP Object type not supported. + * EEBADDATA Sending data with too many nested levels. + * EESENDTO Problem with sendto. + * EEMODENOTSUPP Socket mode not supported. + * EEWOULDBLOCK Operation would block. + * EESEND Problem with send. + * EECALLBACK Wait for callback. + </DL> + + See also: + socket_connect, + socket_create + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/capitalize ds2.1/lib/doc/efun/strings/capitalize *** ds1.1/lib/doc/efun/strings/capitalize Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/capitalize Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + capitalize - capitalize a string + + string capitalize( string str ); + + Convert the first character in 'str' to upper case, and return the + new string. + + See also: + lower_case + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/clear_bit ds2.1/lib/doc/efun/strings/clear_bit *** ds1.1/lib/doc/efun/strings/clear_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/clear_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + clear_bit - zero a bit in a bit string + + string clear_bit( string str, int n ); + + Return the new string where bit 'n' is cleared in string 'str'. Note that + the old string 'str' is not modified. See set_bit() for information on + the format of the string. + + See also: + set_bit, + test_bit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/crypt ds2.1/lib/doc/efun/strings/crypt *** ds1.1/lib/doc/efun/strings/crypt Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/crypt Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + crypt - encrypt a string + + string crypt( string str, string seed ); + + Crypt the string 'str' using the first two characters from 'seed' as + a seed. If 'seed' is 0, then random seed is used. + + The result has the first two characters as the seed. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/explode ds2.1/lib/doc/efun/strings/explode *** ds1.1/lib/doc/efun/strings/explode Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/explode Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + explode - break up a string + + string array explode( string str, string del ); + + explode() returns an array of strings, created when the string 'str' + is split into pieces as divided by the delimiter 'del'. + + EXAMPLE: + + explode(str," ") will return as an array all of the words (separated + by spaces) in the string 'str'. + + See also: + implode, + sscanf, + replace_string, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/strings/implode ds2.1/lib/doc/efun/strings/implode *** ds1.1/lib/doc/efun/strings/implode Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/implode Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + implode - concatenate strings + + string implode( array arr, string del ); + + mixed implode( array arr, function f); + + mixed implode( array arr, function f, mixed start); + + Concatenate all strings found in array 'arr', with the string 'del' between + each element. Only strings are used from the array. Elements that are not + strings are ignored. + + The second version takes the first and second values of arr and passes them + to f, then passes that result and the third arg to f, et cetera. It returns + the last result of the call to f. + + In the third case, the first call is f(start, arr[0]), then things proceed + as above. + + See also: + explode, + sprintf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/index ds2.1/lib/doc/efun/strings/index *** ds1.1/lib/doc/efun/strings/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,28 ---- + String efuns + + The following efuns exist for working with strings: + + <DL> + * capitalize + * clear_bit + * crypt + * explode + * implode + * lower_case + * next_bit + * pluralize + * reg_assoc + * regexp + * replace_string + * set_bit + * sprintf + * sscanf + * strcmp + * stringp + * strlen + * strsrch + * terminal_colour + * test_bit + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/lower_case ds2.1/lib/doc/efun/strings/lower_case *** ds1.1/lib/doc/efun/strings/lower_case Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/lower_case Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + lower_case - return the lowercase version of a given string + + string lower_case( string str ); + + Return the lowercase version of a given string (original string remains + unchanged). + + See also: + capitalize + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/next_bit ds2.1/lib/doc/efun/strings/next_bit *** ds1.1/lib/doc/efun/strings/next_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/next_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + next_bit - find the next bit set in a bitstring + + int next_bit( string str, int n ); + + next_bit() returns the next bit set in a bitstring after 'n', or -1 if + 'n' is the last set bit. + + See also: + set_bit, + test_bit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/pluralize ds2.1/lib/doc/efun/strings/pluralize *** ds1.1/lib/doc/efun/strings/pluralize Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/pluralize Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + pluralize - returns the plural of a given string + + string pluralize( string str ); + + Returns the plural of 'str'. Handles most of the oddities of the English + language. + + This efun is only available if PACKAGE_CONTRIB is defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/reg_assoc ds2.1/lib/doc/efun/strings/reg_assoc *** ds1.1/lib/doc/efun/strings/reg_assoc Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/reg_assoc Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,55 ---- + reg_assoc - A regular pattern substring extractor + + array reg_assoc(string str, string array pat_arr, array tok_arr); + + array reg_assoc(string str, string array pat_arr, array tok_arr, mixed def); + + reg_assoc() takes a string and explodes it into substrings matching + the regular expression pattern strings given in pat_arr and associates + them with tokens given in tok_arr. If def (default 0) is given, it + is associated with a non-match. The return value is an array of + two arrays, the 1st being an array of the form + <pre> + ({ non-match1, match1, non-match2, match2, ..., + non-match n, match n, non-match n+1 }) + </pre> + and the 2nd holds the tokens corresponding to the matches in order: + <pre> + ({ def, token corresponding to match1, ...., def, + token corresponding to match n, def }). + </pre> + + pat_arr and tok_arr must be of the same sizes, the ith element in + tok_arr being the corresponding token to the ith element of pat_arr. + pat_arr can only hold strings. + + If pat_arr (and hence tok_arr) has size 0 then the return value is + simply ({ ({ str }), ({ def }) }). + + EXAMPLE + + <pre> + #define STRING_PAT "\e"(\e\e\e\e.|[^\e\e\e"])*\e"" + #define NUM_PAT "[0\-9]+" + + #define F_STRING 1 + #define F_NUM 2 + + reg_assoc("Blah \e"blah\e" test 203 hhh j 308 \e"bacdcd\eb\e"acb", + ({ STRING_PAT, NUM_PAT }), ({ F_STRING, F_NUM }), "no-match") + </pre> + + will return + + <pre> + ({ ({ "Blah ", "\e"blah\e"", " test ", "203", " hhh j ", "308", " ", + "\e"bacdcd\eb\e"", "acb" }), + ({ "no-match", F_STRING, "no-match", F_NUM, "no-match", F_NUM, + "no-match", F_STRING, "no-match" }) }) + </pre> + + See also: + + regexp [for regular expression syntax] + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/regexp ds2.1/lib/doc/efun/strings/regexp *** ds1.1/lib/doc/efun/strings/regexp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/regexp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,93 ---- + regexp - regular expression handler + + int regexp( string str, string pattern); + + string array regexp( string array lines, string pattern); + + string array regexp( string array lines, string pattern, int flag); + + In the first version, regexp() returns true (1) if the string str contains + a substring which matches the regular expression 'pattern'. If a complete + match is wanted, the pattern should begin with ^ and end with $. + + When presented with an array of lines of text and a regular + expression, regexp() returns an array containing those lines which + match the pattern specified by the regular expression. If the (flag & 2) + is nonzero, (flag defaults to zero), then non-matches will be returned + instead of matches. If (flag & 1) is nonzero, the array returned will be of + the form ({ index1 + 1, match1, ..., indexn + 1, matchn }) where indexn + is the index of nth match/non match in the array lines. + + REGULAR EXPRESSION SYNTAX + + A regular expression is zero or more <b>branches</b>, separated by '|'. + It matches anything that matches one of the branches. + + A <b>branch</b> is zero or more <i>pieces</i>, concatenated. + It matches a match for the first, followed by a match for the second, etc. + + A <b>piece</b> is an <i>atom</i> possibly followed by '*', '+', or '?'. + An atom followed by '*' matches a sequence of 0 or more matches of the atom. + An atom followed by '+' matches a sequence of 1 or more matches of the atom. + An atom followed by '?' matches a match of the atom, or the null string. + + An <b>atom</b> is a regular expression in parentheses (matching a match for the + regular expression), a <i>range</i> (see below), '.' + (matching any single character), '^' (matching the null string at the + beginning of the input string), '$' (matching the null string at the + end of the input string), a '\e' followed by a single character (matching + that character), or a single character with no other significance + (matching that character). + + A <b>range</b> is a sequence of characters enclosed in '[]'. + It normally matches any single character from the sequence. + If the sequence begins with '^', + it matches any single character <b>not</b> from the rest of the sequence. + If two characters in the sequence are separated by '-', this is shorthand + for the full list of ASCII characters between them + (e.g. '[0-9]' matches any decimal digit). + To include a literal ']' in the sequence, make it the first character + (following a possible '^'). + To include a literal '-', make it the first or last character. + + AMBIGUITY + + If a regular expression could match two different parts of the input string, + it will match the one which begins earliest. + If both begin in the same place but match different lengths, or match + the same length in different ways, life gets messier, as follows. + + In general, the possibilities in a list of branches are considered in + left-to-right order, the possibilities for '*', '+', and '?' are + considered longest-first, nested constructs are considered from the + outermost in, and concatenated constructs are considered leftmost-first. + The match that will be chosen is the one that uses the earliest + possibility in the first choice that has to be made. + If there is more than one choice, the next will be made in the same manner + (earliest possibility) subject to the decision on the first choice. + And so forth. + + For example, '(ab|a)b*c' could match 'abc' in one of two ways. + The first choice is between 'ab' and 'a'; since 'ab' is earlier, and does + lead to a successful overall match, it is chosen. + Since the 'b' is already spoken for, + the 'b*' must match its last possibility (the empty string) since + it must respect the earlier choice. + + In the particular case where no '|'s are present and there is only one + '*', '+', or '?', the net effect is that the longest possible + match will be chosen. + So 'ab*', presented with 'xabbbby', will match 'abbbb'. + Note that if 'ab*' is tried against 'xabyabbbz', it + will match 'ab' just after 'x', due to the begins-earliest rule. + (In effect, the decision on where to start the match is the first choice + to be made, hence subsequent choices must respect it even if this leads them + to less-preferred alternatives.) + + See also: + + sscanf, + explode, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/repeat_string ds2.1/lib/doc/efun/strings/repeat_string *** ds1.1/lib/doc/efun/strings/repeat_string Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/repeat_string Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + repeat_string - repeat a string a specified number of times. + + string repeat_string(string, int); + + repeat_string returns a string that consists of its first argument + repeated n times, where 'n' is repeat_string's second argument. + So repeat_string("foo", 3) would return "foofoofoo". + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/replace_string ds2.1/lib/doc/efun/strings/replace_string *** ds1.1/lib/doc/efun/strings/replace_string Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/replace_string Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,47 ---- + replace_string - replace all instances of a string within a string + + string replace_string( string str, string pattern, string replace ); + + string replace_string( string str, string pattern, string replace, int max ); + + string replace_string( string str, string pattern, string replace, int first, int last ); + + replace_string() returns 'str' with all instances of 'pattern' replaced with + 'replace'. If 'pattern' has zero length then str is returned unmodified. + If the resultant string would exceed the maximum string length then + replace_string() returns an undefinedp(), non-stringp() value. + + replace_string() can be used to remove characters from a string by + specifying a pattern and a zero-length replace parameter. For example, + replace_string(" 1 2 3 ", " ", "") would return "123". replace_string() + executes faster this way then explode()/implode(). + + The 4th and 5th arguments are optional (to retain backward compatibility.) + The extra arguments have the following effect: + + With 4 args: + + The 4th argument specifies the maximum number of replacements + to make (the count starts at 1). A value of 0 implies 'replace all', and + thus, acts as replace_string() with 3 arguments would. E.g., + replace_string("xyxx", "x", "z", 2) would return "zyzx". + + With 5 args: + + The 4th and 5th arguments specify the range of matches to replace + between, with the following constraints: + + <DL> + * first < 1 : change all from the start. + * last == 0, or last > max_matches : change all to end + * first > last : return the unmodified array. + </DL> + + E.g., replace_string("xyxxy", "x", "z", 2, 3) returns "xyzzy". + + See also: + sscanf, + explode, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/set_bit ds2.1/lib/doc/efun/strings/set_bit *** ds1.1/lib/doc/efun/strings/set_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/set_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_bit - set a bit in a bitstring + string set_bit( string str, int n ); + + Return the new string where bit 'n' is set in string 'str'. Note that the old string 'str' is not modified. + + The maximum value of 'n' is limited by the value of the 'maximum bits in a bitfield' entry in the driver config file. + + The new string will automatically be extended if needed. + + Bits are packed 6 per byte in printable strings. + + See also: clear_bit , test_bit + + Tim Hollebeek + Beek @ZorkMUD, Lima Bean, IdeaExchange, TMI-2, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/sprintf ds2.1/lib/doc/efun/strings/sprintf *** ds1.1/lib/doc/efun/strings/sprintf Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/sprintf Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,55 ---- + sprintf - formatted output conversion + + string sprintf( string format, ... ); + + An implementation of sprintf() for LPC, with quite a few extensions + Originally implemented by Lynscar (Sean A Reith). + + This version supports the following as modifiers: + <dl> + * " " - pad positive integers with a space. + * "+" - pad positive integers with a plus sign. + * "-" - left adjusted within field size. + <b>Note:</b> sprintf() defaults to right justification, which is unnatural + in the context of a mainly string based language but has been retained for + "compatability". + * "|" - centered within field size. + * "=" - column mode if width is greater than field size. This is only + meaningful with strings, all other types ignore this. Columns are + auto-magically word wrapped. + * "#" - table mode, print a list of '\\n' separated 'words' in a + table within the field size. only meaningful with strings. + * a number - specifies the field size, a '*' specifies to use the + corresponding arg as the field size. If n is prepended with a zero, then + the field is padded zeros, otherwise it is padded with spaces (or specified pad string; see below). + * "." then a number - precision of n, simple strings truncate after this (if precision is + greater than field size, then field size = precision), tables use + precision to specify the number of columns (if precision not specified + then tables calculate a best fit), all other types ignore this. + * ":" then a number - n specifies the fs _and_ the precision, if n is prepended by a zero then the field is padded with zeros instead of spaces. + * "@" - the argument is an array. the corresponding format_info (minus the "@") is applied to each element of the array. + * "'X'" - The char(s) between the single-quotes are used to pad to + field size (defaults to space) (if both a zero (in front of field + size) and a pad string are specified, the one specified second + overrules). NOTE: to include "'" in the pad string, you must + use "\'" (as the backslash has to be escaped past the + interpreter), similarly, to include "\" requires "\\\\". + </dl> + The following are the possible type specifiers. + <dl> + * % - in which case no arguments are interpreted, and a "%" is + inserted, and all modifiers are ignored. + * O - the argument is an LPC datatype. + * s - the argument is a string. + * d, i - the integer arg is printed in decimal. + * c - the integer arg is to be printed as a character. + * o - the integer arg is printed in octal. + * x - the integer arg is printed in hex. + * X - the integer arg is printed in hex (with A-F in capitals). + * f - floating point number + </dl> + + See also: + sscanf + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/sscanf ds2.1/lib/doc/efun/strings/sscanf *** ds1.1/lib/doc/efun/strings/sscanf Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/sscanf Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,43 ---- + sscanf - match substrings in a string + + int sscanf( string str, string fmt, mixed var1, mixed var2, ... ); + + Parse a string 'str' using the format 'fmt'. The format 'fmt' + consists of text to match against 'str', separated by patterns which + begin with '%'. The following patterns are supported: + + <DL> + * '%%' - matches '%' + * '%x' - matches a hexidecimal number + * '%d' - matches a decimal number + * '%f' - matches a floating point number + * '%(regexp)' - matches anything that matches the regular + expression 'regexp' (see the regexp() efun for details) + * '%s' - matches a string; see below + </DL> + + Note that the third and following arguments are NOT expressions; they + must be valid lvalues (locations which can be assigned to). As + matches are encountered in the string, the corresponding values are + put directly into the third and following arguments. If a problem + is encountered (either some of the text between patterns doesn't + match, or a pattern can't be matched to the corresponding input) + the number of matches so far is returned, and the remaining arguments + are left unchanged. If a '*' comes immediately after the '%' in the + format, then that pattern is matched, but not assigned to a variable. + It is counted in the return value. + + '%s' is handled as follows. If it is followed by text, '%s' matches + up the the next ocurrence of the text. For example, the format + "%sxy%s" will match "fox" to the first %s when used on the string + "foxxybarxyz". If the %s occurs at the end of the string, the + remainder of the string is matched. If it is followed immediately + by another pattern, then %s matches up to the first valid match for + the following pattern. "%s%s" is illegal. + + See also: + explode, + replace_string, + strsrch + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/strcmp ds2.1/lib/doc/efun/strings/strcmp *** ds1.1/lib/doc/efun/strings/strcmp Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/strcmp Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + strcmp - determines the lexical relationship between two strings + + int strcmp( string one, string two ); + + This implementatin of strcmp() is identical to the one found in C libraries. + If string one lexically precedes string two, then strcmp() returns a number + less than 0. If the two strings have the same value, strcmp() returns 0. + If string two lexically precedes string one, then strcmp() returns a number + greater than 0. This efunction is particularly useful in the compare + functions needed by sort_array(). + + Note that relational operators (<, >, etc) can also be used to compare + strings. + + See also: + sort_array + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/strlen ds2.1/lib/doc/efun/strings/strlen *** ds1.1/lib/doc/efun/strings/strlen Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/strlen Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,10 ---- + strlen - returns the length of a string + + int strlen( string str ); + + strlen() returns the number of characters in the string 'str'. + + See also: + sizeof + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/strsrch ds2.1/lib/doc/efun/strings/strsrch *** ds1.1/lib/doc/efun/strings/strsrch Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/strsrch Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,19 ---- + strsrch - search for substrings in a string + + int strsrch( string str, string substr | int char, int flag ); + + strsrch() searches for the first occurance of the string 'substr' in the + string 'str'. The last occurance of 'substr' can be found by passing '-1' + as the 3rd argument (which is optional). If the second argument is an + integer, that character is found (like C's strchr()/strrchr().) The empty + string or null value cannot be searched for. + + The integer offset of the first (last) match is returned. -1 is returned + if there was no match, or an error occurred (bad args, etc). + + See also: + sscanf, + replace_string, + regexp + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/terminal_colour ds2.1/lib/doc/efun/strings/terminal_colour *** ds1.1/lib/doc/efun/strings/terminal_colour Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/terminal_colour Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + terminal_colour - replaces codes in a string + + string terminal_colour(string str, mapping m, int wrap, int indent); + + terminal_colour() replaces each occurrence of %^key%^ in str with 'value', + where 'key' and 'value' are the elements in the mapping m. + + 'wrap' is the optional column number to wrap at, and 'indent' is the + amount to indent the second and following lines. Codes are assumed to + change the mode of the terminal and not generate any printable + characters for the purposes of wrapping. + + This efun is only available if PACKAGE_CONTRIB is defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/test_bit ds2.1/lib/doc/efun/strings/test_bit *** ds1.1/lib/doc/efun/strings/test_bit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/test_bit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + test_bit - test a bit in a bitstring + + int test_bit( string str, int n ); + + Returns 1 if bit 'n' was set in string 'str', and zero otherwise. + + See also: + set_bit, + clear_bit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/strings/upper_case ds2.1/lib/doc/efun/strings/upper_case *** ds1.1/lib/doc/efun/strings/upper_case Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/strings/upper_case Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + upper_case - return the uppercase version of a given string + + string upper_case(string); + + Return the uppercase version of a given string (original string remains + unchanged). + + This function requires PACKAGE_CONTRIB to be defined in the options file. + + See also: + capitalize, + lower_case + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/all_previous_objects ds2.1/lib/doc/efun/system/all_previous_objects *** ds1.1/lib/doc/efun/system/all_previous_objects Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/all_previous_objects Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + all_previous_objects - returns an array of objects that called the current function + + object array all_previous_objects(); + + Returns an array of objects that called current function. + Note that local function calls do not set previous_object() to the current + object, but leave it unchanged. + + The first element of the array is previous_object(), followed by + previous_object(1), etc ... + + See also: + call_other, + origin, + previous_object + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/call_out_info ds2.1/lib/doc/efun/system/call_out_info *** ds1.1/lib/doc/efun/system/call_out_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/call_out_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + call_out_info - get pending call_out() information + + array call_out_info(); + + Get information about all pending call outs. An array is returned, + where every item in the array consists 3 elements: the object, + the function, and the remaining delay. + + Note: due to security concerns, and the fact that call_outs may now + have an arbitrary number of arguments, the 4th element of the return + value was returned. The security concerns stem from the fact that if + the arguments where types which can be modified (arrays, mappings, + etc), obtaining them would allow them to be modified before the + function was called. It is possible this will be fixed in the + future if there is enough interest. + + See also: + call_out, + remove_call_out + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/check_memory ds2.1/lib/doc/efun/system/check_memory *** ds1.1/lib/doc/efun/system/check_memory Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/check_memory Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + check_memory - check all allocated blocks + + string check_memory(int flag) + + returns a string describing possible memory allocation problems. If the + optional flag is 1, a summary of allocated memory is printed at the + end. + + This efun is only available if PACKAGE_DEVELOP, DEBUGMALLOC, and + DEBUGMALLOC_EXTENSIONS are defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/ctime ds2.1/lib/doc/efun/system/ctime *** ds1.1/lib/doc/efun/system/ctime Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/ctime Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + ctime - return a time string + + string ctime( int clock ); + + Gives a nice string with current date and time, with the argument 'clock' + that is the number of seconds since 1970. + + See also: + time, + localtime, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/deep_inherit_list ds2.1/lib/doc/efun/system/deep_inherit_list *** ds1.1/lib/doc/efun/system/deep_inherit_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/deep_inherit_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + deep_inherit_list - get a list of ancestors of an object + + string array deep_inherit_list( object obj ); + + Returns an array of filenames of all objects inherited (directly and + indirectly) by obj. + + See also: + inherit_list, + inherits + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/error ds2.1/lib/doc/efun/system/error *** ds1.1/lib/doc/efun/system/error Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/error Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + error - generate a run-time error + + void error( string err ); + + A run-time error 'err' will be generated when error() is called. Execution + of the current thread will halt, and the trace will be recorded to the + debug log. + + See also: + catch, + throw, + error_handler + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/eval_cost ds2.1/lib/doc/efun/system/eval_cost *** ds1.1/lib/doc/efun/system/eval_cost Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/eval_cost Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + eval_cost - returns the evaluation cost remaining + + void eval_cost() + + eval_cost() returns the number of instructions that can be executed + before the driver decides it is in an infinite loop. + + See also: + set_eval_limit, + reset_eval_cost + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/external_start ds2.1/lib/doc/efun/system/external_start *** ds1.1/lib/doc/efun/system/external_start Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/external_start Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,17 ---- + external_start - start an external command + + int external_start(int which, string args, mixed read_cb, mixed write_cb, mixed close_cb); + + 'which' specifies which of the 5 external commands specified in + the config file to run. 'args' are the arguments to pass to the + command. The driver then starts up the specified command, and sets up + an LPC socket to communicate with the input and output of the command. + The file descriptor of the LPC socket is returned. + + See also: + time, + ctime, + localtime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/system/find_call_out ds2.1/lib/doc/efun/system/find_call_out *** ds1.1/lib/doc/efun/system/find_call_out Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/find_call_out Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,14 ---- + find_call_out - find a call out scheduled to be called next + + int find_call_out( string func ); + + Find the first call out due to be executed for function 'func' in the + current object, or the call_out() which returned the integer 'handle', + and return the time left. If it is not found, then return -1. + + See also: + call_out, + remove_call_out, + set_heart_beat + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/flush_messages ds2.1/lib/doc/efun/system/flush_messages *** ds1.1/lib/doc/efun/system/flush_messages Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/flush_messages Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + flush_messages - send all pending messages to a user + + int flush_messages(); + + int flush_messages(object user); + + Normally, messages are queued, then sent all at once to minimize the + number of packets required. This efun forces all pending messages to + be written immediately. If no user is specified, messages for ALL users + are flushed. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/function_exists ds2.1/lib/doc/efun/system/function_exists *** ds1.1/lib/doc/efun/system/function_exists Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/function_exists Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + function_exists - find the file containing a given function in an object + + string function_exists( string str, object ob, int flag ); + + Return the file name of the object that defines the function 'str' in + object 'ob'. The returned value can be other than 'file_name(ob)' if the + function is defined by an inherited object. + + 0 is returned if the function was not defined. + + Note that function_exists() does not check shadows. + + If flag is omitted or zero functions that cannot be called are not returned + (e.g. the function is returned only if call_other(ob, str) would succeed). + If the flag is nonzero, static and private functions are returned too. + + See also: + call_other + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/function_profile ds2.1/lib/doc/efun/system/function_profile *** ds1.1/lib/doc/efun/system/function_profile Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/function_profile Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + function_profile - get function profiling information for an object + + array function_profile( object ob ); + + Returns function profiling information for 'ob', or this_object() if 'ob' + is not specified. This is only available if the driver was compiled + with PROFILE_FUNCTIONS defined. + + An array of mappings is returned, one for each function in 'ob'. The format + of the mapping is: + <pre> + ([ "name" : name_of_the_function, + "calls" : number_of_calls, + + "self" : cpu_time_spent_in self, + "children" : cpu_time_spent_in_children + ]) + </pre> + The usefulness of this is tied to the resolution of the CPU clock--even + though the units are microseconds, the CPU timer resolution is often much + less. + + See also: + rusage, + time_expression + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/functions ds2.1/lib/doc/efun/system/functions *** ds1.1/lib/doc/efun/system/functions Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/functions Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + functions - list all the functions in a given object. + + string array functions(object, int default: 0); + + functions() can return two different things. If the second argument is + 0 (which it is by default) it will return an array containing the names + of all the functions in the object passed as the first argument. If the + second argument is non-zero, more information about each function is + given. For a non-zero second argument, each array element contains + the following: + + ({ function_name, number_of_arguments, return_type, ... }). + + Where the fourth and following elements are the argument types. If + the save_types pragma was not in effect when the function was compiled, + number_of_arguments will be correct, but no types will be available. + + This efun is only available if PACKAGE_CONTRIB is defined in the + options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/index ds2.1/lib/doc/efun/system/index *** ds1.1/lib/doc/efun/system/index Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/index Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,36 ---- + System efuns + + <DL> + * all_previous_objects + * call_out_info + * check_memory + * ctime + * debug_message + * deep_inherit_list + * error + * eval_cost + * external_start + * find_call_out + * flush_messages + * function_exists + * function_profile + * functions + * inherit_list + * inherits + * localtime + * lpc_info + * max_eval_cost + * memory_summary + * named_livings + * program_info + * reclaim_objects + * replace_program + * reset_eval_cost + * set_eval_limit + * set_reset + * shutdown + * time + * uptime + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/inherit_list ds2.1/lib/doc/efun/system/inherit_list *** ds1.1/lib/doc/efun/system/inherit_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/inherit_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + inherit_list - get a list of parents of an object + + string array inherit_list( object obj ); + + Returns an array of filenames of objects inherited by obj. + If COMPAT_32 was compiled in, this behaves like deep_inherit_list(), + otherwise it behaves like shallow_inherit_list(). + + See also: + deep_inherit_list, + shallow_inherit_list, + inherits + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/system/inherits ds2.1/lib/doc/efun/system/inherits *** ds1.1/lib/doc/efun/system/inherits Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/inherits Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + inherits - determine if an object inherits a given file + + int inherits( string file, object obj ); + + inherits() returns 0 if obj does not inherit file, 1 if it inherits the + most recent copy of file, and 2 if it inherits an old copy of file. + + See also: + deep_inherit_list, + inherit_list + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/system/localtime ds2.1/lib/doc/efun/system/localtime *** ds1.1/lib/doc/efun/system/localtime Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/localtime Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,38 ---- + localtime - convert to local time + + array localtime( int time ); + + localtime() converts a time value (as returned by time()) into an array + of values which represents the time locally. In the past time() was used + to get the time in GMT (UTC), and then local definitions were used to + determine the local offset from GMT. This roundabout approach is no + longer necessary. localtime() returns the seconds, minutes and hours, + the day, month and year, day of the week, day of the year, + the name of the local timezone and how far the MUD is from GMT. This + information is retrieved directly from the operating system and made + available to the driver without the use of MUD-specific configuration + files. + + localtime() returns an array containing the values specified above. + The index for each value is defined symbolically in localtime.h. The + following table summarizes the array returned by localtime(). + <pre> + int LT_SEC Seconds after the minute (0..59) + int LT_MIN Minutes after the hour (0..59) + int LT_HOUR Hour since midnight (0..23) + int LT_MDAY Day of the month (1..31) + int LT_MON Months since January (0..11) + int LT_YEAR Year (guarenteed to be >= 1900) + int LT_WDAY Days since Sunday (0..6) + int LT_YDAY Days since January 1 (0..365) + int LT_GMTOFF Seconds after GMT (UTC) + string LT_ZONE Timezone name + </pre> + + See also: + ctime, + time, + time_expression, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/lpc_info ds2.1/lib/doc/efun/system/lpc_info *** ds1.1/lib/doc/efun/system/lpc_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/lpc_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,8 ---- + lpc_info - return information about LPC->C compiled objects + + string lpc_info(); + + lpc_info() returns a string describing which LPC->C programs are available, + which are loaded, and which are out of date with respect to their source. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/max_eval_cost ds2.1/lib/doc/efun/system/max_eval_cost *** ds1.1/lib/doc/efun/system/max_eval_cost Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/max_eval_cost Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + max_eval_cost - returns the maximum evaluation cost + + void max_eval_cost() + + max_eval_cost() returns the number of instructions that can be executed + before the driver decides it is in an infinite loop. + + See also: + set_eval_limit, + reset_eval_cost + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/memory_summary ds2.1/lib/doc/efun/system/memory_summary *** ds1.1/lib/doc/efun/system/memory_summary Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/memory_summary Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,24 ---- + memory_summary - return a summary of memory usage + + mapping memory_summary(); + + memory_summary() returns a mapping of the form: + + PRE( + ([ + program name : ([ + var name : mem usage, + ... + ]) + ... + ]) + ) + + the memory usage is the memory required to store the value divided by the + number of variables pointing to that particular value. [Due to sharing + of values, giving an exact number for the memory usage of any + value is impossible] + + This efun is only available if PACKAGE_CONTRIB is defined. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/named_livings ds2.1/lib/doc/efun/system/named_livings *** ds1.1/lib/doc/efun/system/named_livings Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/named_livings Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + named_livings - return all living objects with names + + mapping named_livings(); + + named_livings() returns all objects that have called both set_living_name() + and enable_commands(). It is significantly more efficient than livings(). + + named_livings() is available if PACKAGE_CONTRIB is defined, and NO_ADD_ACTION + is not. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/program_info ds2.1/lib/doc/efun/system/program_info *** ds1.1/lib/doc/efun/system/program_info Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/program_info Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + program_info - returns information about program memory usage + + string program_info(); + + string program_info(object ob); + + Returns a summary of the memory usage of the program for a given object. + If no program is specified, a summary of the memory usage of all loaded + programs is returned. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/reclaim_objects ds2.1/lib/doc/efun/system/reclaim_objects *** ds1.1/lib/doc/efun/system/reclaim_objects Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/reclaim_objects Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,16 ---- + reclaim_objects - reclaim any lingering objects + + int reclaim_objects(); + + Cycles through all objects that are loaded, and frees any lingering objects + that it can. This could result in a sizable amount of memory being freed up, + depending on how the mud is coded. Objects are typically left lingering + when a global variable in more than one object contains a pointer to it, + and the object gets destructed, but the values containing pointers to the + object are never accessed again. This efun returns the number of destructed + objects encountered in variables. + + See also: + destruct + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/replace_program ds2.1/lib/doc/efun/system/replace_program *** ds1.1/lib/doc/efun/system/replace_program Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/replace_program Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + replace_program - replaces the program in this_object() + + void replace_program( string str ); + + replace_program() replaces the program in this_object() with that of an + object it inherits. The string argument is the filename of the object + whose program is to be used. Once the replacement takes place, the current + object effectively becomes a clone of that other object, but with its + current filename and global variable values. The program is not actually + replaced until the current execution is completed. + + Note that one effect of this is that all functions defined in the object + no longer exist, being replaced by the functions in the inherited program, + so this routine should not be called if one of those functions might be + called later (and in particular, create() needs to exist if you intend to + clone from the object). + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/replaceable ds2.1/lib/doc/efun/system/replaceable *** ds1.1/lib/doc/efun/system/replaceable Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/replaceable Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + replaceable - determine whether any functions are defined in at this level + + int replaceable(object ob); + + int replaceable(object ob, string array fnames); + + In the second form, return 0 if the program for object ob defines any + functions explicitly, as opposed to simply inheriting. Function names + in the array fnames are ignored. If no such functions are defined, 1 + is returned. If the second argument is omitted, it defaults to + ({ "create" }). The purpose of this efun is to assist in making + automatic decisions on whether to call replace_program(). Note that + the default version ignores create(), so it is only safe to replace a + object for which replaceable() returns true if you never intend to + clone from that object. + + See also: + replace_program, + functions, + function_exists, + inherit_list + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/reset_eval_cost ds2.1/lib/doc/efun/system/reset_eval_cost *** ds1.1/lib/doc/efun/system/reset_eval_cost Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/reset_eval_cost Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,12 ---- + reset_eval_cost - resets the evaluation cost remaining + + void reset_eval_cost(); + + reset_eval_cost() resets the evaluation cost remaining to the maximum + evaluation cost. + + See also: + eval_cost, + set_eval_limit + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/set_eval_limit ds2.1/lib/doc/efun/system/set_eval_limit *** ds1.1/lib/doc/efun/system/set_eval_limit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/set_eval_limit Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + set_eval_limit - set the maximum evaluation cost + + void set_eval_limit( int ); + + set_eval_limit(), with a nonzero argument, sets the maximum evaluation + cost that is allowed for any one thread before a runtime error occurs. + With a zero argument, it sets the current evaluation counter to zero, + and the maximum cost is returned. set_eval_limit(-1) returns the + remaining evaluation cost. + + See also: + eval_cost + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/system/set_reset ds2.1/lib/doc/efun/system/set_reset *** ds1.1/lib/doc/efun/system/set_reset Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/set_reset Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,18 ---- + set_reset - modify the time until reset on an object + + varargs void set_reset( object ob, int time ); + + This efun is only available if NO_RESETS is not compiled in. + + Sets the time until reset on 'ob' to 'time' seconds from now. If 'time' + is omitted, the driver's normal reset time setting formula is applied + to 'ob', that is, + <pre> + reset time = current_time + reset_time / 2 + random(reset_time / 2) + </pre> + + See also: + reset + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/system/shallow_inherit_list ds2.1/lib/doc/efun/system/shallow_inherit_list *** ds1.1/lib/doc/efun/system/shallow_inherit_list Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/shallow_inherit_list Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,15 ---- + shallow_inherit_list - get a list of parents of an object + + string array shallow_inherit_list( object obj ); + + Returns an array of filenames of objects inherited by obj. Only directly + inherited files are returned. E.g. if A inherits B which inherits C, + inherit_list(A) will return an array with B, but not C. + + See also: + deep_inherit_list, + inherit_list, + inherits + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/system/shutdown ds2.1/lib/doc/efun/system/shutdown *** ds1.1/lib/doc/efun/system/shutdown Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/shutdown Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + shutdown - shutdown the driver + + void shutdown( int how ); + + This function shuts down the driver in a controlled fashion (as opposed to + how a crash would shut it down). The 'how' argument specifes what integer + value that driver should pass to exit(). The convention is to pass 'how' + as -1 when the script that restarts the driver should die as well. Thus + a reboot command would use shutdown() while a halt command would use + shutdown(-1). The script must explicitly check the return value to see + if it is -1 if you wish to use this convention. Obviously, shutdown() + is a sensitive function and should be secured. As with exec(), the way + to make it secure is to add a simul_efun of the same name which does + the appropriate security checks. Be sure to set valid_override() up + (in master.c) to protect against efun::shutdown(). + + See also: + crash, + slow_shutdown, + valid_override + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere + diff -c -r --new-file ds1.1/lib/doc/efun/system/time ds2.1/lib/doc/efun/system/time *** ds1.1/lib/doc/efun/system/time Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/time Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,11 ---- + debug_message - send a message to the driver's stdout + + void debug_message(string); + + The string argument is printed on the driver's stdout, as well as being added + to the debug.log file. + + See also: + ctime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/uptime ds2.1/lib/doc/efun/system/uptime *** ds1.1/lib/doc/efun/system/uptime Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/uptime Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + uptime - return the number of seconds elapsed since the last driver reboot + + int uptime(); + + This function returns the number of seconds since the last driver reboot. + + See also: + time, + ctime, + localtime, + time_expression + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/efun/system/variables ds2.1/lib/doc/efun/system/variables *** ds1.1/lib/doc/efun/system/variables Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/efun/system/variables Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + variables - list all the variables in a given object. + + string array variables(object, int default: 0); + + variables() can return two different things. If the second argument is + 0 (which it is by default) it will return an array containing the names + of all the variables in the object passed as the first argument. If the + second argument is non-zero, more information about each variable is + given. For a non-zero second argument, each array element contains + the following: + + ({ variable_name, variable_type }). + + Where variable_name is the name of the given variable, and variable_type + is the type of the variable, such as "string" or "private int" etc. + + This efun is only available if PACKAGE_CONTRIB is defined in the + options file. + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/faq/admin ds2.1/lib/doc/faq/admin *** ds1.1/lib/doc/faq/admin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/faq/admin Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,778 ---- + Dead Souls Admin FAQ, v2 + + Written by Cratylus @ Frontiers, October 2005 + Updated January 2006 + + %^GREEN%^*** What's this FAQ about? ***%^RESET%^ + + The point of this document is to orient a new admin in + Dead Souls 2. Starting a MUD with a lib that is completely new to + you can be confusing and discouraging. Hopefully this FAQ will + make the experience less difficult. + + + %^GREEN%^*** How do I start?***%^RESET%^ + + Start by reading the Dead Souls FAQ for some background + on where this lib came from and what you can do with it. + + + %^GREEN%^*** What's the QCS?***%^RESET%^ + + Please see the QCS example page for an explanation of this + important Dead Souls system. + + + %^GREEN%^*** Is there a MUD somewhere running Dead Souls I can log into?***%^RESET%^ + + As a convenience to the curious, I have set up a "demo" mud + at dead-souls.net 6666 . To connect, either click on + this link with your browser, or open a terminal window + (or for windows users, Start -> Run ) and + type: telnet dead-souls.net 6666 + + When you log in, the system will read your playerfile for + a few seconds and then it will turn you into a creator. This + is so that you can examine code, try out the QCS, etc. + + Please note that in the regular, non-demo version of the + mud, people are NOT automatically given creator status. + + On the regular non-demo version of the mud, Only + the admin (basically, the first person to log on to the new mud) + gets automatic creatorship. Another difference is that the + demo mud is set to reboot every eight hours or so. The + default reboot interval on the regular version is weeks long. + + After logging in, you will be transported + to your workroom. Some useful commands: + + look + look at me + look at chest + open chest + look in chest + get tricorder from chest + read index in handbook + read chapter 1 in handbook + who + stat + wiz + create new npc generic + look at board + read 1 on board + home + + + %^GREEN%^*** I want to invite my friends to help me code. How do I + promote them to creator status?***%^RESET%^ + + As admin, you have access to the admintool + command. This opens a menu-driven admin system you + can use to manage some basic aspects of your new MUD. + + Everything on admintool can be done with + commands, system calls, or file editing, but until + you get the hang of all that stuff, admintool + is a convenient shortcut. + In this example, you would type: admintool , + then select option 3, then option l (that's a lowercase "L"). + + The oldfashioned way, if the new creator + were named dude, would be: encre dude + + I know. But people like menus, so I made it. + + + %^GREEN%^*** What about intermud? How do I talk on that?***%^RESET%^ + + The intermud3 (or i3) network is available + to you, and you are probably already connected to it. Type + mudlist to see a list of other muds on the network. + + By default, the "Dead Souls intermud channel" is + enabled for creators. Type: ds blah blah + and other Dead Souls muds on the i3 network will see + your message like this: + + You@YourMud <ds> blah blah + + To enable intergossip and intercre, read + /doc/README for instructions. + + Please note that intercre is where you ask coding + and technical questions only. Random chatting is not + tolerated on that channel. Newbie questions that are + Dead Souls specific or that obviously have answers in + Dead Souls documentation will meet a hostile reception on + intercre. + + Conversely, intergossip is mostly chat. Please + be warned that discussions on intergossip are usually + offensive, argumentative, and generally aggressive. + This hostility is especially sharp when you + are identified as a "newbie". You will almost certainly + be mocked and insulted no matter what you say, but + especially if your first messages betray you as + ignorant of intergossip standards and traditions. I + strongly recommend you lurk on this channel for a few + days before saying anything. Really, I recommend you + avoid it entirely. + + + %^GREEN%^*** I talk on intermud but nobody replies. What's up with that?***%^RESET%^ + + I3 uses a hub topology. All muds communicating on intermud + connect to the router to do so. If that router is down all + I3 communication stops, until it comes back up. + + There's also the possibility that nobody who wants to + chat is listening. + + + %^GREEN%^*** What's this about a manual on Frontiers?***%^RESET%^ + + It's no longer relevant. All the docs + we were making available on Frontiers are now included + in Dead Souls, starting from version 1.9r9. + + In your workroom is a chest. Open the + chest and the new Dead Souls Creators Manual is + inside. The text files are in /doc/manual . + + + %^GREEN%^*** How do I add limbs to a race?***%^RESET%^ + + Edit /secure/cfg/races/<race>, then remove the race from the + races daemon, then add re-add the race. If you want players + to be able to play as this race, make sure you add the + numeral 1 on the addrace command. For example: + + addrace jabberwock 1 + + + %^GREEN%^*** How do I make my friend an admin?***%^RESET%^ + + Use the groups menu in admintool, and select + "Modify a group". Select the ASSIST or SECURE group, + and enter the names of all the members it should have. If + I wanted to make xyzzy an assistant admin, I would edit the + ASSIST group and make the contents look like this: + + cratylus:xyzzy + + Xyzzy then needs to log out and log back in. + + Obviously, Xyzzy needs to be a creator for this to be of any use, + so I would have encre'd him first. + + + %^GREEN%^*** I don't like how the who command output looks! How can I change it?***%^RESET%^ + + Believe it or not, I actually get questions like this. I also + get stuff like "my workroom is broken! fix it!" + + If there is something broken about the lib itself, such as + an insta-death bug or a command that crashes the mud, I am + happy and eager to hear about it, so I can implement the fix + in the next lib release. + However, if the problem you're having is that the lib, + by design, behaves in a way not to your liking, this isn't something + I'm likely to "fix" for you. For example, if you want a "who" + command with a cooler look, that's up to you to make. You're + the one coding a mud, so you need to take it upon yourself to + understand the code and modify it to suit your tastes. + Similarly, "orcs are too strong!" or "advancing levels + should increase your eyesight" are issues you need to deal + with on your own, using the coding skills learned from reading the + Creators Manual. + + + %^GREEN%^*** All I did was change one thing in a file, and now it won't update. Help!***%^RESET%^ + + You should make it a habit to make backup copies of files + before editing them. That way, if you screw up the code, you can + just copy the backup to the original filename. + + A convenient way to do this is the bk command. See + the debugging page for an example of its use. + + If you are using Windows, you need to be aware of the + linefeed problem. unix text files and DOS text files have different + formatting. If you edit files in Notepad, then try to update them, + you may find that the file no longer updates, no matter what + you do. The difference is usually invisible to you, so you can't + tell why a file that looks exactly the same as before now won't + work. + + Dead Souls expects unix-formatted text, and if you feed it + something else, the results aren't likely to be to your + satisfaction. Make sure you use an editor that respects unix + text. In Windows 2000, WordPad seems to do a reasonable job of not + completely screwing things. It does, however, add carriage + returns to your lines, so when you look at them in ed, you'll + see a bunch of "^M"'s all over the place. + + If you still have trouble, take a look at the debugging page. + + + The mud editor is confusing the heck out of me. It's too hard to use. + + Check out the MUD Editor tutorial. It should ease the pain a little. + + + %^GREEN%^Can you please make the FAQ easier to read? It's too long and complicated.***%^RESET%^ + + I'm a lib coder, not a web designer. Cut me slack. Or, edit it + for me and show me how it's done. + + + %^GREEN%^*** How can I change the colors of the channel messages?***%^RESET%^ + + The colors are specified in /secure/daemon/chat.c + + + %^GREEN%^*** How do I know what other muds use Dead Souls?***%^RESET%^ + + + Go to the arch room. Type: arch + + Then type: read screen + + This shows a list of muds that used Dead Souls and + joined intermud at some point. To see a list that + also includes obvious test muds, type: read printout + + + %^GREEN%^*** I was hanging out in the Arch room and the loudspeaker went off. WTF?***%^RESET%^ + + Your mud receives all sorts of network requests from the + intermud network, such are remote who (asking who is logged on), + remote finger (info on users), locate (trying to find a user + somewhere on i3), etc. Whenever your mud receives such a request, + it is announced in the Arch room. Note that these are normal, + and do not represent an attempt to undermine your security. + + + %^GREEN%^*** I want to test the intermud channel but I don't want to spam the ds line.***%^RESET%^ + + Type: call me->AddChannel("ds_test") + Then type: ds_test test + + The ds_test channel is specifically for communication + testing so that ds can remain spam free. + + + %^GREEN%^*** The web server and FTP server don't work***%^RESET%^ + + To enable them at mud boot time, uncomment the "inet" line in + /secure/cfg/preload.cfg + + To enable it temporarily, type: update /secure/daemon/inet + + These server do not use the standard ports. The internet standard + http port is 80 and for ftp it is 21. Your mud ftp and web servers + do not use these. + Instead, the network port for your web server is 5 less + than your mud's port, and the ftp port is 1 less. + This means that if your mud is reached by telnetting + to port 6666, your ftp server will be at 6665 and your web server + will be at 6661. + + Please note that the web and ftp server are not supported. They work, + but whatever security risk they pose is entirely on you. + + + %^GREEN%^*** I tried to log in to the FTP server but I can't!***%^RESET%^ + + Make sure you use your mud name and mud password, not the + username and password of the computer you are on. + + + %^GREEN%^*** I can't do anything with FTP. It just hangs there.***%^RESET%^ + + FTP is a funny sort of protocol. If you don't have a direct + connection to an FTP server (for example, you are behind a + firewall), you have to use PASV (or passive) mode. Unfortunately, + at this time, PASV is not implemented in the mud FTP server. + + + %^GREEN%^*** The web server gives me a 404 but I know the directory is there.***%^RESET%^ + + Like the FTP server, the web server is a very simple program. + It does not do directory listings at all. If you request + a directory, and it can't find an "index.html" file, it + just errors out. + + Let me make this point one final, excruciatingly clear time: + If you need a webserver, use apache. The mud www server is available + as a convenience, not as a production-quality standards-compliant + intarweb server. + + + %^GREEN%^*** Where can I get a Dead Souls mud hosted?***%^RESET%^ + + That's a heck of a good question. There are many mud hosting services + out there. I hear good things about Kyndig, but that isn't specific + to Dead Souls. A good host will have a high level of service, shell + and file transfer access, etc, for which you obviously will need + to pay money. There ain't no such thing as a free lunch. + + + %^GREEN%^*** I moved a command from one directory to another. How do I get the new location recognized?***%^RESET%^ + + First, run update on the command in question. + then: + If it's not a verb: update /daemon/command + If it's a verb: update /daemon/verbs + + + %^GREEN%^*** The mudtime is all wrong!***%^RESET%^ + + The mudtime command tells you what time it is in the game, not what time + it is in the real world. + + + %^GREEN%^*** The time of day is all wrong!***%^RESET%^ + + If you used admintool to change your timezone and the time of day is still + wrong, you may be using an OS with timekeeping that Dead Souls doesn't + understand. If this is so, figure out how many hours off you are, and + enter that value into the EXTRA_TIME_OFFSET parameter in /secure/include/config.h + + + %^GREEN%^*** Hey this is supposed to run on Windows but it doesn't!***%^RESET%^ + + There are three main causes for this: + + 1) You are using Windows 98, Me, or below. That's unsupported and won't work. + + 2) You edited secure/cfg/mudos.cfg with a Windows-style editor and now the driver can't read it. + Copy the original mudos.cfg over the hosed one. If you need to change the mud's name, + don't edit mudos.cfg. Use the admintool command. + + 3) You are trying to run Dead Souls in a directory other than c:\ds + + + %^GREEN%^*** What happened to the roommaker and thingmaker?***%^RESET%^ + + They produced code that was often incompatible with QCS. They are no + longer supported. + + + %^GREEN%^*** I keep getting 'Connection to address server (localhost 9999) refused.' ***%^RESET%^ + + This is a harmless error. Dead Souls uses a program called addr_server to + try to resolve hostnames. However, hostname resolution is not important + to running the mud, so it's not automatically configured. If you run + addr_server with a specific port as an argument, and edit mudos.cfg to + point to that port for the addr_server, then reboot the mud, then you + will probably have hostname resolution in your mud. + + However, not all OS'es handle name resolution the same, so this may not + work, even if you do everything exactly right. Either way, it doesn't + affect the mud. + + + %^GREEN%^*** Every now and then I use a QCS command and it fails, then I try again later and it works. WTF?***%^RESET%^ + + This is a rather frustrating issue, because it happens very rarely + and when it does, the error data is limited. Please email me a log + of what happened so I can analyze it. + + + %^GREEN%^*** When I log in, everything is screwed up, and I can't do anything!***%^RESET%^ + + This happens sometimes when you log out while carrying an object + with broken code. If for example, you are wearing a vest, and then you + edit the code for it, but it doesn't work anymore, then you log out, + what happens is the next time you log in the mud will try to restore an + item in your inventory that throws an error, and your login + gets stuck halfway. + + If you find that when you log in things are all screwed up for + you, use the rescue login feature. For me, this means I would + login as cratylus_rescue instead of cratylus. My inventory + will get wiped before my playerfile is loaded, and I'll + be able to log in with no problems. + + + %^GREEN%^*** Can I charge players a fee for playing on my mud?***%^RESET%^ + + NO. + + Dead Souls uses MudOS, and MudOS has a license that specifically + and strictly forbids its use in a commercial way. I don't care how + you use the lib, but if you use it with MudOS, you need to comply + with MudOS licensing. If you were to port Dead Souls to some other + driver that allows commercial use, then you'd be all set. + + %^GREEN%^*** Can people donate money to me for the mud?***%^RESET%^ + + Yes. + + So long as there is no quid-pro-quo, or anything + about the transaction that is legally regarded as "commercial", + receiving money from people for the purpose of running the + mud is ok. However, I am not a lawyer, so read the MudOS + license yourself. + + + %^GREEN%^*** I found a bug. For real. Can you please fix it?***%^RESET%^ + + Email me: <put my name here>@comcast.net + + Please include a detailed description of the bug, and the exact + error text and commands that produced it. A log file or + screencap would be helpful. + + + %^GREEN%^*** How are files organized in Dead Souls?***%^RESET%^ + + cd / and ls to view the top level directory. The + list may be largely meaningless to you, so let's review it here: + + cfg/ + + General configuration files for timezone and such. + + cmds/ + + Main location of commands that don't require special access + privileges. Commands are different from verbs in that they tend + not to manipulate your environment, but rather deal with + the player's relationship to the system and/or files. + + + daemon/ + + Daemons are files that provide access to data files in an + organized way. For example, adding an occupational class + (like, say, assassin) to the game needs to be done in a + precise way in order for it not to break things. By sending + the data to the daemon first, you can be sure that the + new system configuration is entered properly. Daemons also + provide a means to access data, like "how much is silver + worth compared to gold", that is uniform across the mud, and + prevents accidental overwrites of data files by multiple + editors. + + + doc/ + + General documentation. + + + domains/ + + This is where MUD game areas go when they are complete + and ready for general play by the public. Once here, only + admins have write access to the files. + + + ftp/ + + The base for the MUD ftpd. Using the ftpd is probably dangerous + in terms of your system security, and I discourage it, but if + you are determined to have mud ftp access for your creators, + this is one way. See /secure/lib/net for the actual server. It + may or may not work. I won't support it. + + + include/ + + Include files provide a set of constants for your files. For + example, if you include <damage_types.h>, you can specify in + the code for your chainmail that it protects against + the damage type "BLADE" at a certain level. + + + lib/ + + This is the heart of the Dead Souls lib. This is the location + of the files that your objects, be they swords, shoes, or + handguns, will use as their configuration base. + + + log/ + + Log files. + + + news/ + + Announcements are made here. For example, in /news/creator + you can post a notice that you have added a teleportation + spell, and when your creators log on, they will see the message. + + + obj/ + + Contains some important templates, especially some for the QCS. + + open/ + + Legacy directory. Kept for compatibility. Historically this + directory has served as a place where creators can put code + for others to freely modify. + + + realms/ + + This is where creator home directories are. + + + save/ + + Files that describe properties of the MUD's systems live + here. The number of limbs that a bat has, for example, + is in races.o. In classes.o you'll find the skill ranges + for fighters. Do not edit these files. They must be + modified by daemons only, or you risk corrupting them. + + + secure/ + + This directory will be described in a separate section below. + + + shadows/ + + Shadows are a controversial feature of LPC. This directory + is designed for shadow objects, but they should be very + rarely, if ever used. Basically shadow objects are objects + that attach themselves to another object, intercepting + function calls. For obvious reasons this is a security + risk, so unless you really really know what you're doing, + avoid them. + + + spells/ + + Pretty self explanatory. The spells daemon looks for spells here. + + + tmp/ + + A directory anyone can write to. Generally for swapping + data between objects, systems, or people. + + + verbs/ + + Another controversial topic. Verbs are a kind of command. For + example, go and sit and open are verbs. Specifically, verbs + are commands that interact with the user's environment. The + idea is that throw my first red rock at the green goblin + should work, and should work the same everywhere on the + MUD. Verbs are a source of debate among some people, because + to folks accustomed to add_action commands, verbs seem + excessively complex. + + www/ + + Like the ftp directory, but for the MUD webserver. + + + Ok now let's take a quick look at the /secure directory: ls /secure + As you can see, /secure seems to have many of the same directories + that the root filesystem has. + The reason a /secure directory is needed is that + there are files that should not be readable by everyone, and + there are files that must be writable only by a few. The MUD security + system uses the /secure directory as a means to control access to + such files. + For example, the average creator has no business + accessing the player data files of other creators or players. Therefore + /secure/save/creators and /secure/save/players is offlimits to them. + + A directory without a counterpart in / is /secure/sefun. This + is where simulated external functions reside. + + + %^GREEN%^*** What are sefuns and efuns?***%^RESET%^ + + First let me explain that the driver has built-in + functions that are available to the mud. For example, + type eval return find_player("cratylus") , but replace my name + with yours. Your player object pointer will be found and returned + to you (more or less. strictly speaking it's more complicated). + The driver provides this function. Because it is "external" + to the mudlib, that is, it's in the driver and not the lib, + it is called an external function, or more commonly, "efun". The + idea is that certain actions you ask the mud to perform are + so common that they are made available MUD-wide. + + Efuns are ridiculously useful and powerful, and because + they are in the driver as compiled code, very fast. A near-complete + set of efun documentation is available in /doc/efun. + + However, the driver does not contain every possible + MUD-wide function you might want. For example, there is a + tell_object() efun, which lets you send a message to an object + such as a player. The syntax is something like this: + + tell_object(find_player("cratylus"),"Hi."); + + Which doesn't look like much, but believe me, this + kind of stuff adds up. I wanted to make this simpler, so I + used what is called a sefun, or a simulated efun. It is + a function that is available lib-wide, but it isn't in + the driver. Instead it is provided by the lib itself (the + master daemon, specifically). By adding the appropriate code + in /secure/sefun/ I have now made available a tell_player() sefun, + which works like this: + + tell_player("cratylus","Hi.") + + This simplification of code will become more obviously + useful to you as you get more coding under your belt. Most + sefuns are documented in /doc/sefun. + + + + %^GREEN%^*** Whew! Ok now I know where stuff is. What's next?***%^RESET%^ + + You probably want to examine how objects are written. + Type goto /domains/town/room/road and wander around town + a bit. If you want to see the code for something, for example, + the beggar, about beggar should do it, provided the beggar is + in the room. + + To see the filenames of the objects around you, + type scan here, or scan me to scan your own inventory. + + If you've never coded before, this is the hard part. + To understand what you're looking at when you run commands like + more /domains/town/weap/orcslayer.c you need to get comfortable + with LPC. + The brute force way of doing this is copying stuff + and then changing the descriptions, thus making new stuff. + This will work, but you'll waste time looking for examples of + exactly what you want to do..and you may not find them. + Instead, learning LPC will let you create whatever + you want, without relying on templates. + + This means that now you must read the LPC Basic + manual, then the LPC Intermediate manual. As admin, your + creators will expect you to know what's in there. + + On your person or in the chest in your workroom is + the Creators Manual. Read both the Players Handbook and + the Creators Manual from cover to cover. + + + %^GREEN%^*** Oh, man, you're kidding! Those are, like, books! Can't I + just start making stuff?***%^RESET%^ + + Well...ok. But you need to go through the docs + soon, ok? In the meantime, read the QCS chapters in the + Creators Manual to get you quick-started in the creation + process. Remember you need to be holding your Creator + Staff in order to access the QCS commands. + + Other useful tools in your chest are a remote + control and a medical tricorder. + + + %^GREEN%^*** Everything is su-u-u-u-p-e-e-r-r-r s-s-l-o-o-o-o-w-w-w***%^RESET%^ + + First, make sure you are using the latest available version of + Dead Souls (check here or here). Older versions of Dead Souls + are known to have nasty memory leaks. + + Next, see if you have runaway objects. An object can be coded + to do really unpleasant stuff like replicate itself over and + over until it brings the mud to its knees. Find out how many + objects are loaded by typing: eval return sizeof(objects()) + + If the count is in the thousands, and only a few people are + logged on, you've got a runaway. Most often this involves + NPC's doing stuff you didn't expect. Destroy all loaded npc's + with the following command: + eval return filter(objects(), (: inherits("/lib/npc",$1) :))->eventDestruct() + + If the lag clears up, you found the culprit. If not, see if + the callouts list is clogged with the command: callouts + + If all else fails, reboot the mud and ask for help on the ds line. + + Please note that the rage virus (especially if unleashed + in the menagerie) is notorious for redlining the mud. Having + hundreds of NPC's all engaging in simultaneous combat + while infecting each other with a rapidly spreading hostility + virus can be expected to impact overall performance. So please try + to avoid the rage virus unless you are specifically stress testing + your system. + + + %^GREEN%^*** Is Dead Souls secure?***%^RESET%^ + + The short answer is no, nothing I know of is "secure" in the + sense that you don't need to continually pay attention to it. If the + question is "Is Dead Souls particularly unsafe to run?" then the + answer is no. Just like any other Internet program you use, Dead Souls + is not an obvious security risk, so long as it is not used carelessly. + And, obviously, games of any kind, including Dead Souls, should never + be installed on any mission-critical, national security, public + safety, or health care server. + + Dead Souls security involves two separate spheres: + + 1) The binary executable and the system that runs it. + + 2) The mudlib and the code that you use and create. + + The first sphere is probably most important. Presumably + you plan to run a mud on a computer that does other things too, + and you want to keep those things separate from your mud. The + most important thing to do is to avoid running Dead Souls as a + privileged user. In the case of Windows, this means that the + program should not be run by Administrator or anyone in the + Administrator group. + For unix users, this means that the driver should not run + under uid 0 (root). + + The reason for this precaution is that if some genius + hacker manages to exploit some unknown weakness in the program, + it is better that the process they hack doesn't have full admin + privileges to the box. + This caution has little to do with Dead Souls specifically. + It is a warning I'd give to anyone planning to run any kind of network + server. You should take your own security seriously, and + if you do not understand your own security situation, you need to take + a step back and ask yourself if running a mud at all is a good idea. + + Sphere 2 is lib security. In older muds, file and directory + privileges were handled by attributes on the files. If a file's + user id (UID) matched a user's UID, then that user had full access + to it. Such systems often had complex systems that evaluated + effective UID (EUID) based on the file's attributes, its parent + directory, the user's ID, possibly group id, etc. This is an + entirely valid security model, but because of its complexity, + it tended to be exploited easily and often. If you don't + stay 100% on top of such a system (just like any OS), there's + no way to be sure you won't rooted. + + With stack security, privilege management is much, much + easier. A file's privilege is based solely on its location. If + a user doesn't have read access to /foo/bar/ then she can't read + or modify /foo/bar/file.c. If someone with privs to that location + copies the file to somewhere else, then the privs of that new location + are in force on the file. + The "stack" part of stack security comes from the mud + evaluating the privileges of all the objects involved in the + access request. If you're unprivileged and you manage to get a + privileged object to make the access request for you, the access + will fail, because you are unprivileged, and you are still part + of the function call stack (i.e., the list of instructions that + form a chain between the command and the intended event). + + Granular (more detailed) modification of user privileges + can be done by changing files in /secure/cfg to grant + users and groups specific privileges. + + - Cratylus + + Dead Souls Homepage + diff -c -r --new-file ds1.1/lib/doc/faq/ed ds2.1/lib/doc/faq/ed *** ds1.1/lib/doc/faq/ed Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/faq/ed Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,518 ---- + The ed Editor + + + This has always been the aspect of coding that new + creators have most trouble with. It's what discourages most + people from creating lots of stuff, in fact. + + With Dead Souls, you can get away with avoiding ed + most of the time, by using the room maker and the thing maker. + + But to add special functions to your code, like + magic items, smart NPC's (aka mobs), traps, hidden objects, + etc, you need to use ed, if you're going to be editing inside + the mud. + + ed is a simple editing program. It is designed to + work on a line-by-line basis, so it is called a "line editor". + + Let's start by looking at, and editing, a small file. + We've coded a sword, and we want to change its description + from "short sword" to "plain sword": + + + + > %^GREEN%^cd /realms/cratylus/area/weap%^RESET%^ I changed my working directory to my area weapons dir + /realms/cratylus/area/weap: + > %^GREEN%^ls%^RESET%^ I listed the contents of that dir: + /realms/cratylus/area/weap/: + 1 dagger.c 1 nco_sword.c~ 1 std_sword.c~ + 1 gsword.c 1 sharpsword.c 1 sword.c + 001 gsword.c~ 1 staff.c + 1 nco_sword.c 1 std_sword.c + + + > %^GREEN%^ed sword.c%^RESET%^ I ran the ed command on the file sword.c. + /realms/cratylus/area/weap/sword.c, 641 bytes + :%^GREEN%^n%^RESET%^ This makes the editor display line numbers next to the lines. + number on, list off + :%^GREEN%^1z%^RESET%^ This lists about 20 lines of text + 1 /* /domains/Examples/weapon/sword.c + 2 * from the Nightmare IV LPC Library + 3 * a simple sword example, nothing fancy + 4 * created by Descartes of Borg 950402 + 5 */ + 6 + 7 #include <lib.h> + 8 #include <damage_types.h> + 9 #include <vendor_types.h> + 10 + 11 inherit LIB_ITEM; + 12 + 13 static void create() { + 14 item::create(); + 15 SetKeyName("short sword"); + 16 SetId( ({ "sword", "short sword" }) ); + 17 SetAdjectives( ({ "short" }) ); + 18 SetShort("a short sword"); + 19 SetLong("A cheap and rather dull short sword."); + 20 SetMass(150); + 21 SetDollarCost(50); + 22 SetVendorType(VT_WEAPON); + :%^GREEN%^z%^RESET%^ + 22 SetVendorType(VT_WEAPON); + 23 SetClass(20); + 24 SetDamageType(BLADE); + 25 SetWeaponType("blade"); + 26 } + :%^GREEN%^15%^RESET%^ I displayed line 15 + 15 SetKeyName("short sword"); + :%^GREEN%^15c%^RESET%^ I used 'c' to replace line 15 + 15. * %^GREEN%^SetKeyName("plain sword");%^RESET%^ I entered my replacement text + 16. * %^GREEN%^.%^RESET%^ I entered a single dot on a blank line + : + 16 SetId( ({ "sword", "short sword" }) ); + :%^GREEN%^1z%^RESET%^ I listed about 20 lines, starting from line 1 + 1 /* /domains/Examples/weapon/sword.c + 2 * from the Nightmare IV LPC Library + 3 * a simple sword example, nothing fancy + 4 * created by Descartes of Borg 950402 + 5 */ + 6 + 7 #include <lib.h> + 8 #include <damage_types.h> + 9 #include <vendor_types.h> + 10 + 11 inherit LIB_ITEM; + 12 + 13 static void create() { + 14 item::create(); + 15 SetKeyName("plain sword"); + 16 SetId( ({ "sword", "short sword" }) ); + 17 SetAdjectives( ({ "short" }) ); + 18 SetShort("a short sword"); + 19 SetLong("A cheap and rather dull short sword."); + 20 SetMass(150); + 21 SetDollarCost(50); + 22 SetVendorType(VT_WEAPON); + :%^GREEN%^18%^RESET%^ I displayed line 18 + 18 SetShort("a short sword"); + :%^GREEN%^18c%^RESET%^ I started the replacement of line 18 + 18. * SetShort("a plain sword"); I entered my replacement text + 19. * . I entered a single dot on a blank line + :%^GREEN%^1z%^RESET%^ I displayed about 20 lines starting from line 1 + 1 /* /domains/Examples/weapon/sword.c + 2 * from the Nightmare IV LPC Library + 3 * a simple sword example, nothing fancy + 4 * created by Descartes of Borg 950402 + 5 */ + 6 + 7 #include <lib.h> + 8 #include <damage_types.h> + 9 #include <vendor_types.h> + 10 + 11 inherit LIB_ITEM; + 12 + 13 static void create() { + 14 item::create(); + 15 SetKeyName("plain sword"); + 16 SetId( ({ "sword", "short sword" }) ); + 17 SetAdjectives( ({ "short" }) ); + 18 SetShort("a plain sword"); + 19 SetLong("A cheap and rather dull short sword."); + 20 SetMass(150); + 21 SetDollarCost(50); + 22 SetVendorType(VT_WEAPON); + :%^GREEN%^x%^RESET%^ I saved and exited + "/realms/cratylus/area/weap/sword.c" 26 lines 633 bytes + Exit from ed. + > %^GREEN%^update sword%^RESET%^ I loaded the file into memory + /realms/cratylus/area/weap/sword: Ok + + + + Let's take this step by step: + + 1) I changed my working directory to my area weapons dir: %^GREEN%^cd /realms/cratylus/area/weap%^RESET%^ + + 2) I listed the contents of that dir: %^GREEN%^ls%^RESET%^ + + 3) I ran the ed command on the file sword.c: %^GREEN%^ed sword.c%^RESET%^ + + 4) Within the editor, I issued the '%^GREEN%^n%^RESET%^' command. This makes the editor + display line numbers next to the lines. + + 5) Within the editor, I issued the '%^GREEN%^1z%^RESET%^' command. What '%^GREEN%^z%^RESET%^' does is display + about 20 lines of the file (the exact number depends on your screen + settings. In my case it's 22). If you happen to be looking at line 1, it + will display lines 1 through to about 20. If you happen to be looking + at line 40, it will display from line 40 to about 60. + If you want to start looking at lines starting at line 15, you + can issue the '%^GREEN%^15z%^RESET%^' command, which basically means "display about 20 + lines starting at line 15". + In this case, I wanted to start from the beginning of the file, + so I issued '%^GREEN%^1z%^RESET%^'. + + 6) '%^GREEN%^1z%^RESET%^' stopped listing the file at line 22, so I entered '%^GREEN%^z%^RESET%^' again to + list the rest. + + 7) Since I want to change "short sword" to "plain sword", I examined each + line to find the word "short". I noticed that line 15 has "short" in it, + so to get a look at that line alone, I entered '%^GREEN%^15%^RESET%^'. + + 8) Now that I'm sure line 15 needs to change, I issue the '%^GREEN%^15c%^RESET%^' command. + '%^GREEN%^c%^RESET%^' indicates that I want to change a line. '%^GREEN%^15c%^RESET%^' means "delete whatever + was in line 15, and replace it with what I am about to type". + + 9) You can see that my editor prompt changed from ":" to "*". What this + means is that I am now in "input mode". Whatever I type now will be + added to the file. Since my last command in "command mode" was '%^GREEN%^15c%^RESET%^', + I am now replacing that line with what I want the line to contain: + %^GREEN%^SetKeyName("plain sword");%^RESET%^ + + 10) Ok, I replaced the line, but I'm still in input mode. To go back to + command mode, I type a single period and enter, like this: + %^GREEN%^.%^RESET%^ + + 11) I'm back in command mode now. When I list the file contents with + '%^GREEN%^1z%^RESET%^' I can see that line 15 now says what I wanted. + + 12) Now I see another line that needs changing, so I enter '18' to + get a closer look. + + 13) Sure enough, 18 needs to change, so I issue '%^GREEN%^18c%^RESET%^'. + + 14) Like I did for line 15, I enter what the line should be. + + 15) To return to command mode, I enter a single period on a blank line. + + 16) I list the file contents, and see that my change was successful. + + 17) I'm finished making my changes, so I issue the '%^GREEN%^x%^RESET%^' command. '%^GREEN%^x%^RESET%^' + means "save the changes I have made, and exit the editor". + + 18) I am now at my regular command prompt. To load my changes to this + file, I type '%^GREEN%^update sword%^RESET%^'. + + + Editor basics, part 2 + + + In the last section you saw what a simple line + replacement looks like in ed. Next we'll talk about some common + ed actions. + + ADDING STUFF: + + Suppose I want to specify that this sword requires only + one hand to wield it: + + + > %^GREEN%^ed sword.c%^RESET%^ started the editor + /realms/cratylus/area/weap/sword.c, 633 bytes + :%^GREEN%^n%^RESET%^ enabled line number printing + number on, list off + :%^GREEN%^15,22%^RESET%^ listed lines 15 to 22 + 15 SetKeyName("plain sword"); + 16 SetId( ({ "sword", "short sword" }) ); + 17 SetAdjectives( ({ "short" }) ); + 18 SetShort("a plain sword"); + 19 SetLong("A cheap and rather dull short sword."); + 20 SetMass(150); + 21 SetDollarCost(50); + 22 SetVendorType(VT_WEAPON); + :%^GREEN%^20a%^RESET%^ appended to the file after line 20 + 21. * %^GREEN%^SetHands(1);%^RESET%^ entered my added text + 22. * %^GREEN%^.%^RESET%^ single dot on a blank line to exit input mode + :%^GREEN%^18,22%^RESET%^ displayed line 18 through 22 + 18 SetShort("a plain sword"); + 19 SetLong("A cheap and rather dull short sword."); + 20 SetMass(150); + 21 SetHands(1); + 22 SetDollarCost(50); + :%^GREEN%^x%^RESET%^ exited editor and saved + "/realms/cratylus/area/weap/sword.c" 27 lines 646 bytes + Exit from ed. + + + + Here you can see that instead of '%^GREEN%^c%^RESET%^', which replaces, I + used '%^GREEN%^a%^RESET%^', which adds. I decided my new line would go after line + 20, so I issued the command '%^GREEN%^20a%^RESET%^'. Once I was done, I typed + a single dot on a blank line to exit "input mode". You'll notice + I didn't use the '%^GREEN%^z%^RESET%^' command. Instead, since I knew where my + changes would go, I decided to list lines 18 through 22 with + the command '%^GREEN%^18,22%^RESET%^'. I then issued the '%^GREEN%^x%^RESET%^' command to save my + changes and exit the editor. + If had I wanted my addition to go in front of line 20, + I could have used the '%^GREEN%^20i%^RESET%^' command. + + DELETING LINES + + Suppose I'm tired of seeing header lines that no + longer apply to this file. We can delete a single line, or + a range of lines, with the '%^GREEN%^d%^RESET%^' commmand: + + > %^GREEN%^ed sword.c%^RESET%^ + + /realms/cratylus/area/weap/sword.c, 646 bytes + :%^GREEN%^n%^RESET%^ enabled line number printing + number on, list off + :%^GREEN%^1,10%^RESET%^ listed lines 1 to 10 + 1 /* /domains/Examples/weapon/sword.c + 2 * from the Nightmare IV LPC Library + 3 * a simple sword example, nothing fancy + 4 * created by Descartes of Borg 950402 + 5 */ + 6 + 7 #include <lib.h> + 8 #include <damage_types.h> + 9 #include <vendor_types.h> + 10 + :%^GREEN%^1,5d%^RESET%^ deleted lines 1 to 5 + :%^GREEN%^1,5%^RESET%^ listed (the new) lines 1 to 5 + 1 + 2 #include <lib.h> + 3 #include <damage_types.h> + 4 #include <vendor_types.h> + 5 + :%^GREEN%^1d%^RESET%^ deleted blank line 1 + :%^GREEN%^1z%^RESET%^ displayed the file starting at line 1 + 1 #include <lib.h> + 2 #include <damage_types.h> + 3 #include <vendor_types.h> + 4 + 5 inherit LIB_ITEM; + 6 + 7 static void create() { + 8 item::create(); + 9 SetKeyName("plain sword"); + 10 SetId( ({ "sword", "short sword" }) ); + 11 SetAdjectives( ({ "short" }) ); + 12 SetShort("a plain sword"); + 13 SetLong("A cheap and rather dull short sword."); + 14 SetMass(150); + 15 SetHands(1); + 16 SetDollarCost(50); + 17 SetVendorType(VT_WEAPON); + 18 SetClass(20); + 19 SetDamageType(BLADE); + 20 SetWeaponType("blade"); + 21 } + :%^GREEN%^x%^RESET%^ exited and saved + "/realms/cratylus/area/weap/sword.c" 21 lines 476 bytes + Exit from ed. + + + + First I deleted lines 1 through 5 with the command '%^GREEN%^1,5d%^RESET%^'. + Then, for good measure, I removed the remaining blank line '%^GREEN%^1d%^RESET%^'. + Voila. Cleaner code. + + REPLACING STRINGS + + Well now I want to replace all instances of "short" with + "plain", and I don't feel like editing each matching line + manually. I can do a search and replace. First I will list which + lines need to change, then I will change them: + + > %^GREEN%^ed sword.c%^RESET%^ + + /realms/cratylus/area/weap/sword.c, 476 bytes + :%^GREEN%^n%^RESET%^ enabled line number printing + number on, list off + :%^GREEN%^g/short/p%^RESET%^ searched for and displayed lines containing "short" + 10 SetId( ({ "sword", "short sword" }) ); + 11 SetAdjectives( ({ "short" }) ); + 13 SetLong("A cheap and rather dull short sword."); + :%^GREEN%^g/short/s/short/plain %^RESET%^ searched for "short" and replaced with "plain" + :%^GREEN%^g/short/p%^RESET%^ searched for "short" again but found none + :%^GREEN%^1z%^RESET%^ listed file from line 1 + 1 #include <lib.h> + 2 #include <damage_types.h> + 3 #include <vendor_types.h> + 4 + 5 inherit LIB_ITEM; + 6 + 7 static void create() { + 8 item::create(); + 9 SetKeyName("plain sword"); + 10 SetId( ({ "sword", "plain sword" }) ); + 11 SetAdjectives( ({ "plain" }) ); + 12 SetShort("a plain sword"); + 13 SetLong("A cheap and rather dull plain sword."); + 14 SetMass(150); + 15 SetHands(1); + 16 SetDollarCost(50); + 17 SetVendorType(VT_WEAPON); + 18 SetClass(20); + 19 SetDamageType(BLADE); + 20 SetWeaponType("blade"); + 21 } + :%^GREEN%^1%^RESET%^ moved to line 1 + 1 #include <lib.h> + :%^GREEN%^I%^RESET%^ ran automatic indentation + Indenting entire code... + Indentation complete. + :%^GREEN%^1z%^RESET%^ listed file from line 1 + #include <lib.h> + #include <damage_types.h> + #include <vendor_types.h> + + inherit LIB_ITEM; + + static void create() { + item::create(); + SetKeyName("plain sword"); + SetId( ({ "sword", "plain sword" }) ); + SetAdjectives( ({ "plain" }) ); + SetShort("a plain sword"); + SetLong("A cheap and rather dull plain sword."); + SetMass(150); + SetHands(1); + SetDollarCost(50); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLADE); + SetWeaponType("blade"); + } + :%^GREEN%^x%^RESET%^ exited and saved + "/realms/cratylus/area/weap/sword.c" 21 lines 488 bytes + Exit from ed. + + + + The command %^GREEN%^g/short/p%^RESET%^ showed me all the lines + that contained the substring "short". Then I ran the global + search and replace command to substitute "plain" for "short", + :%^GREEN%^g/short/s/short/plain%^RESET%^ + Then I searched again for the string "short" and + nothing came up, because it had been replaced. + + Finally I went to line number 1 and issued the 'I' + command. This auto-indents the code, making it neater and + easier to read. + + + Editor basics, part 3 + + + Now let's look at some common problems: + + + 1) %^CYAN%^Accidental deletion%^RESET%^ + + + If you type %^GREEN%^1,20d%^RESET%^ when you meant to type %^GREEN%^1,2d%^RESET%^ you will end + up with a file 18 lines shorter than you intended. ed does not + have an "undo" command, so those lines will never come back. + However, if you quit the editor *without saving*, then that + deletion will not be committed to the file. You can issue the '%^GREEN%^Q%^RESET%^' + command: + + :%^GREEN%^Q%^RESET%^ + + To force quit without saving. Of course, if those lines + weren't already in the file, this won't help much. + + + 2) %^CYAN%^Can't leave the editor%^RESET%^ + + + You try to write and exit, but get this: + + :%^GREEN%^x%^RESET%^ + File command failed. + + What this means is that for some reason, you can't write + to the file, so you don't exit the editor. What this usually means is that + you tried to edit a file that does not belong to you. Since you do not + have permission to modify the file, ed refuses to commit your changes. + + There are two ways around this. If you don't really care + whether your changes are saved or not, you can just force quit the + editor with '%^GREEN%^Q%^RESET%^': + + :%^GREEN%^Q%^RESET%^ + Exit from ed. + + Your changes will be lost, but you'll be out of the editor. + + If you really want to save this file, you'll have to save it + somewhere other than your current working directory (cwd). You can save + it to your home directory with the 'w' command, then force quit: + + :%^GREEN%^w /realms/cratylus/sword.c%^RESET%^ + "/realms/cratylus/sword.c" 20 lines 478 bytes + :%^GREEN%^Q%^RESET%^ + Exit from ed. + + + 3) %^CYAN%^Indent command fails%^RESET%^ + + + You try to auto-indent your code but get an error like this: + + :%^GREEN%^I%^RESET%^ + Indenting entire code... + Unterminated string in line 13 + Indentation halted. + + This is pretty self explanatory. Indent relies on a certain + amount of coherence in your code, and if your syntax is sufficiently + munged, it can't figure out how to properly do its thing. + Examine the line that indent complains about, and also the + line before it. Sometimes a good line is accused of being bad, just + because it comes after a bad line. + + + 4) %^CYAN%^I need to [something] in ed, but don't know how!%^RESET%^ + + + While in command mode, type '%^GREEN%^h%^RESET%^' and enter. You'll get + a handy list of ed commands available to you. + + + 5)%^CYAN%^ My ability/patience/time is limited. I want not to use ed.%^RESET%^ + + + I feel your pain. The currently available ways around + this are: + + 1) Shell account. If you can get shell, or command line access + to the computer that is running the mud, then you can probably + use an editor local to that computer (like vim) to edit files. + Chances are, though, that if you are a regular rank-and-file + creator, you will not be given shell access. Most system admins + consider giving random people off the net shell access + an abomination. + + 2) Server FTP/SFTP. The server that runs the mud might have an + ftp server or sftpd access. Again, most security-conscious sysadmins + will not permit Just Some Person Off The Internet to have this + kind of access. + + 3) Mud FTP. I don't like this option. Unix FTPD is a security + concern as it is. Using unsupported, un-warrantied mud network code + to provide ftp access to files seems to me to be equivalent to pulling + down your pants, bending over, and whistling for the Internet to + come visit. But...it's an option. + + 4) Client upload. This is actually the most sensible option, if + you are truly allergic to ed. You still need to use ed, but what + you can do is write your code in your favorite local editor, like + notepad or gvim or whatever. Then use your mud client (most of them + have an option to "send text") to send the code by running ed, + entering input mode, copying the code from your editor, and + pasting it into your client. + This is a somewhat awkward system, and ill-suited to + making minor changes. But it has the virtue of working well and + being a widely available option. + + 5) Suck it up. Really, you need to just get used to it. Don't + make me tell you stories about how when I was younger I had to + code using a VT terminal with no cut-and-paste, in an unheated, + locked computer lab 20'x10' in size, at 9600 bps. In a snowstorm. + Uphill both ways. + + diff -c -r --new-file ds1.1/lib/doc/faq/general ds2.1/lib/doc/faq/general *** ds1.1/lib/doc/faq/general Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/faq/general Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,180 ---- + Dead Souls FAQ, v2 + + Written by Cratylus @ Frontiers, October 2005 + Updated January 2006 + + %^GREEN%^ What is Dead Souls? %^RESET%^ + + Primarily Dead Souls is a "mudlib". There is also a Dead Souls + MUD, but this is not what people generally mean when they refer to Dead Souls as a + game. It also happens that a book by the Russian author Nikolai Gogol is named Dead + Souls. That book is wholly unrelated to the Dead Souls software. + + %^GREEN%^ What is it for? %^RESET%^ + + It's for building a game. If what you want to do is play a game, + you're looking for something else. + + %^GREEN%^ What is a MUD? %^RESET%^ + + A MUD is a computer program that uses text (very rarely do MUDs + use graphics or sound) to describe virtual environments you can manipulate. + You enter a command, the program tells you how the virtual world responds + around you. Typically there are other people connected to the same program + over the Internet, and you can interact with them as well. A MUD can be mostly + social, or mostly game oriented, with quests and puzzles to solve or + villains to defeat. The name MUD is an acronym that originally stood for + "Multi-User Dungeon", in accord with the "Dungeons and Dragons" style of + many early MUDs. Now it stands for different things to different people, + but the basic concept of operation is the same, whether the game is set + on the moon, in Manhattan, or in Middle Earth. + + %^GREEN%^ What's a mudlib? %^RESET%^ + + Generally there are two main parts to the MUD program. First is the + "driver". This is an executable program file (in Windows, you'd see the driver + has an .EXE extension) that enables the input and output of data, accepts + network connections, performs basic calculations, etc. The other part + is the mudlib, or, more properly, MUD object library. This is usually a + large set of files in plain text that the driver reads and uses as a + basis for the game. Some files provide information about rooms and + environments, some files provide information about objects or creatures, + etc. When players connect, the driver provides them the world that these + files describe. + + %^GREEN%^ When I configure Dead Souls, it says it is a MUD. If it is really a mudlib, + why would that be? %^RESET%^ + + Dead Souls is not intended to be a fully-developed MUD when you + install it. Instead it provides you with the basic framework you need to + make a MUD of your own. After you set up Dead Souls, you should rename it, + and customize the lib (that is, library) files to create your own world. When + you first run Dead Souls, you will have some rooms available to explore. + This is not your mud. It is just a set of sample places and objects to help + you understand how to build a MUD of your own. So in a way, Dead Souls provides + you a kind of "starter" MUD, but since it's just examples, you can't really + consider it a MUD until you change it to suit your creative vision. + + %^GREEN%^ Is Dead Souls really Nightmare in disguise? %^RESET%^ + + Let's break this question down into its components: + + %^GREEN%^ What is Nightmare? %^RESET%^ + + Nightmare was a mud. It was part of a branching of mud development + that occurred early in the days of popularized mudding. Some folks + decided to take MUD library development in a particular direction, + and eventually made available what is now known as the Nightmare mudlib. + Nightmare went through a few major changes, most notably from version 3 + to version IV. By that time, the development of Nightmare was solely + managed by a coder who called himself Descartes. + + %^GREEN%^ What is the relationship between Nightmare and Dead Souls? %^RESET%^ + + It appears that Dead Souls began as a "development" MUD. This means + that while Descartes ran his own MUD, he also worked on improving that MUD's + lib. It is unwise to make major changes to a MUD that people are playing on, + so the Dead Souls development MUD was one which served as a platform to + develop, extend, and improve the Nightmare lib without risking harm to active players. + Sometime after the release of the Nightmare IV mudlib, Descartes decided to + withdraw it from distribution. Based on their interpretation of copyright + law, people now do not distribute the Nightmare mudlib on Internet servers. + However, somewhat inexplicably, Descartes released the mudlib for his + development mud, Dead Souls, into the public domain. This meant that the + Dead Souls mudlib was completely free to be used by anyone in any way they + chose, be it distribution, modification, spindling or folding. Because Dead + Souls was the development mud for Nightmare Mud, which was the base of the + Nightmare mudlib, the relationship between the two is an extremely close one. + + %^GREEN%^ How close? %^RESET%^ + + Frankly, almost identical. A close comparison of the Dead Souls lib + that Descartes released (version 1.1pre) against the last released Nightmare + lib (IVr6) reveals that they are very nearly the same thing, file for file. + The main differences between the two are: + + * A small number of Nightmare library files aren't on Dead Souls. + * Dead Souls doesn't come with the driver or install script the Nightmare had. + * All documentation files were removed from Dead Souls. + * "Nightmare" in file headers was changed to say "Dead Souls" + + This might sound like a lot of difference, but consider this: not counting + documentation, Nightmare IVr6 lib contained 1064 files and directories, and + the Dead Souls 1.1pre lib contains 1082. Dead Souls 1.1pre actually had more + lib material in it than the last release of Nightmare. + + %^GREEN%^ Why mess with Dead Souls, then? %^RESET%^ + + The main problem was that Dead Souls was a bear to set up. Because + driver development had not stopped (the driver is a separate software project), + but lib development had, incompatibilities grew in number over time. Using + the original driver from 1997 created a MUD that lacked important features + of modern muds, and risked instability. Using a modern driver required a + modification of fundamental lib systems that required some expertise to + perform. People stopped using Nightmare because they couldn't get it, and + they didn't use Dead Souls because the damn thing didn't work right. My own + Nightmare lib MUD, Frontiers, continued to chug along, quietly fading into + obscurity along with all other Nightmare IV based MUDs, while scrappy young + newcomers like CoffeeMud lib started elbowing their way into the MUD community. + + Then a funny thing happened. I really got into lib coding. I mean, full-on + lib obsession. I can't really explain it, other than to say that when I was + younger it seemed hard and impenetrable, but now that I've been working in a + technical field for years, I have the mental tools (and patience) required to + disassemble and understand complex systems. I got turned on by analyzing and + understanding stuff that I'd considered over my head in years past. But I + realized I was living in the past. I couldn't share my exciting lib ideas + and discoveries with anyone else, because the Nightmare LPC community was + in the very last stages of extinction. + + I decided to do something about it. Maybe I'd be whistling into the wind, + tilting at windmills, or even worse, just talking to myself. But I decided + I'd make Dead Souls a viable lib for people to use, because it would be fun, + and because it might be nice to have other people to bounce ideas off of and + steal code from. At worst, I'd be doing nothing more pathetic than, say, + building model ships in my basement. At best, I might revive a once-thriving + MUD development community. Either way, it sounded like an enjoyable project, + so I proceeded. + + %^GREEN%^ Fine, but what's so special about Nightmare/Dead Souls? Why are you making such a + big deal of wanting people to use it? It isn't better than everything else, + surely. [insert mudlib name here] is newer and has [insert feature here] and [other feature]! %^RESET%^ + + Yes, that may be. My experience with other libs is limited, and I'm sure + that Dead Souls pales in comparison to others in one feature or another. My only + answer to that is, go ahead and use the lib you're comfortable with. I make no + claims of superiority. Hell, I'll be the first to admit there are still things + to fix and systems to implement. But if you are not sure which lib to pick, + Dead Souls is an excellent choice as a solid, stable, flexible and powerful platform + to build your MUD. You can do anything in a MUD with LPC, and I mean anything. + If you happen to have Nightmare experience, Dead Souls will be a homecoming... + like an old comfortable shoe....but without the holes or the stink. + + %^GREEN%^ What's LPC? %^RESET%^ + + LPC is a kind of programming language. Dead Souls lib files don't + just contain descriptions of places and things: they have a format that describes + their relationships to the driver and permits you to do fancy stuff...pretty much + any text MUD thing you can think of, you can do in LPC. + + %^GREEN%^ How do I get started? %^RESET%^ + + Download the latest version from http://dead-souls.net/ + or http://www.mudmagic.com/codes/download/lpc/mudos/dead_souls and + install it. There are versions available for Windows and for Unix. The main + difference between the two is the driver. The Windows driver is a Windows + executable. The Unix driver is in source code form and must be compiled. + The lib files for both versions are identical. + + Once you log in, read the Players Handbook and the Creators Manual. + + + %^GREEN%^ Anything else? %^RESET%^ + + Read the Dead Souls Admin FAQ. + + + The end. + + Dead Souls Homepage + diff -c -r --new-file ds1.1/lib/doc/faq/lpmud ds2.1/lib/doc/faq/lpmud *** ds1.1/lib/doc/faq/lpmud Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/faq/lpmud Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,1814 ---- + + LPMUD FAQ + + Last Modified 95/11/30 + + The LPMud FAQ was originally authored 7 November 1994 by George Reese. + It could not, however, have been completed on the efforts of a single + person. See the credits section for a full list of contributors. To + make comments or suggestions on this FAQ, mail borg@imaginary.com. + + Copyright (c) 1994-1995 George Reese. + _________________________________________________________________ + + This is a list of Frequently Asked Questions asked about LPMuds and + the newsgroup devoted to them, rec.games.mud.lp. This FAQ is posted + twice a month to rec.games.mud.lp, rec.games.mud.announce, + news.answers, and rec.answers. All readers are strongly advised to + read this FAQ before posting questions to the LPMud news group, as + your question may already be answered in here. + + This FAQ is not intended to be a substitute for the general 3 part mud + FAQ's. I strongly recommend people new to muds read those first. This + FAQ deals with a particular class of muds known as LPMuds, and + therefore does not even attempt to cover information important to + other classes of muds. + _________________________________________________________________ + + The LPMud FAQ is divided into four sections: + + * Section I: Introduction + + * Section II: Playing LPMuds + + * Section III: Coding on an LPMud + + * Section IV: Starting Your Own LPMud + + + _________________________________________________________________ + + Section I + + INTRODUCTION + + Contents + 1. What sort of posts belong in rec.games.mud.lp? + 2. What is an LPMud? + 3. Isn't Amylaar an LPMud? + 4. Which is the real LPMud? + 5. How did LPMuds get started? + 6. What do the terms "alpha testing", "beta testing", and "fully + open" mean? + 7. Where are some ftp sites with LPMud stuff? + 8. Is there anything about muds on WWW? + 9. What are some mud related mailing lists? + + + _________________________________________________________________ + + + + What sort of posts belong in rec.games.mud.lp? + + ALMOST anything dealing with LPMuds. Rule number 1 being that the + topic of your posts must someway affect the LPMud community. We do not + care about Dikus and MOOs and so on. They may be very nice servers, + but if we wanted to be reading about them, we would be reading + rec.games.mud.diku and so on. The second rule is to avoid posting on + the following topics: + + * Where is CheeseMUD? I have not been able to connect all day! + If it is going to be down a long time, the admins should post + to rec.games.mud.announce. Otherwise, it is either a short + connection loss or it is just your problem. Do not post these + questions here or anywhere!!! + + * Advertisements for muds + These belong in the newsgroup rec.games.mud.announce + + * FascistMUD's admins are such jerks!!! They ... + Why would you post this? I guarantee you will accomplish + nothing by this. First of all, ALL mud admins have bad days + where they may do something very unfair. It is the nature of + things. So you may be the unfortunate victim of a rare set of + circumstances rather than of a mean admin. Secondly, even if + the mud admin is a jerk, no one on this newsgroup cares. People + will play such muds either because the admin is damn good at + creating a game or because the players are other jerks who like + the atmosphere of lawlessness. Players like you may login from + time to time, but eventually they will figure it out. + + * Do not post mudsex sessions + An individual's sexual activities are not matters for public + derision. How people choose to express themselves sexually is a + private issue as long as only consenting adults are involved. + + + _________________________________________________________________ + + + + What is an LPMud? + + An LPMud is one of many classes of muds, or multi-user domains. A + multi-user domain is defined solely with respect to its ability to + allow multiple real individuals to come together in some sort of + environment. Although the most common environment is a gaming + environment, muds need not be games. In fact, among other uses of MUDs + that I know of, there are virtual colleges, a mud where victims of + abuse can come together in a productive environment, and muds designed + to bring students with disabilities into social contact with one + another and others. The single defining theme for mud is therefore + being a virtual environment where multiple people come in contact. + + An LPMud specifically allows the users to manipulate the environment + through a language called LPC. LPMuds are computer programs which + listens to the internet for people attempting to connect, reads LPC + files, and acts upon those LPC files according to the rules of the LPC + language to create the virtual environment. Currently, I know of 6 + major LPMud servers: + + * CD + + * DGD + + * LPC4 + + * LPMud + + * MudOS + + * Shattered World + + * Urimud + + + + With most other mud games, users do not have access to create in the + language used by the mud. LPC is used not only to give users such an + ability, but it is also designed with both ease and power in mind. + _________________________________________________________________ + + + + Isn't Amylaar an LPMud? + + Amylaar is a person, not an LPMud. He is the primary author and torch + bearer of the LPMud name. Given the generic sound of the term "LPMud" + these days, people often refer to LPMud 3.2 as the Amylaar driver. + _________________________________________________________________ + + + + Which is the real LPMud? + + LPMud 3.2 is the official continuation of the original LPMud server, + however, all servers listed above (with the possible exception of + Urimud) are equally real. All have two traits that make a mud an + LPMud: + 1. The environment is created through files written in LPC. + 2. The environment can change as new files are added and old ones + changes, even while the game is running. + + + _________________________________________________________________ + + + + How did LPMuds get started? + + I am not the greatest historian, and may be wrong on some important + facts here, but this is the first shot at the FAQ, so here goes... + Once upon a time, there was Lars Pensjö (the ö being an o with two + dots over it... to an American, that is roughly pronounced "Penscha"), + who wrote the original LPMud coming from an AberMUD background. If you + play current LPMud's of the LPMud type, you won't really notice much + of a difference from the original. From the coders' point of view + however, LPC is nothing like it was with the original. For a long + time, there was only LPMud run by Lars with patches by everyone under + the sun. The original LPMud run by Lars was called Genesis. Its base + town called Larstown was taken mostly from AberMUD. + + Eventually, others got tired of waiting to see their patches added to + Lars' driver, and Lars was working on version 3.0 of his driver as he + was gradually losing interest in the project altogether. Version 3.0 + turned out to be buggy as hell, and generally unworkable for a real + LPMud. CD, LPC4, LPMud, and MudOS, all derive from this server as + people saw good things in it and began creating working versions of + LPMud 3.0 after their own concepts of mud server design. + + Unlike the others, DGD was created from scratch. It therefore is + missing a lot of the baggage which has come down from the beginning of + time in the other drivers. Urimud, on the other hand, is derived from + LPMud 2.4.5. + _________________________________________________________________ + + + + What do the terms "alpha testing", "beta testing", and "fully open" mean? + + Generally, a mud goes through three basic stages. The first stage, + "alpha testing", is a developmental mode in which players are rarely + allowed access to the mud. Things are in such a disarray or in a + flurry of changes that playing a consistent game is impossible. In the + "beta testing" stage, a mud is generally opened to players solely for + the sake of testing that the mud works. Without actual play testing, + it is impossible to determine if a mud can handle being fully open. + muds in either of the above stages generally will not compensate + players for mishaps due to bugs in the game, and they will often even + purge players from the mud. The purging is done either because old + player objects are no longer compatible with new ones or because the + mud needs to be re-balanced to fit new code. + + In the final stage, "fully open", a mud is just that, fully open. That + means you can expect certain standards from the mud, including such + things as not dying from bugs. Nothing is ever bug free, so generally + fully open muds will compensate players for mishaps which occur + because of a bug. On the flip side, these muds usually also smite + players who gain from bugs in the system. + _________________________________________________________________ + + Where are some ftp sites with LPMud stuff? + + See Section IV: Where can I find all of this stuff? + _________________________________________________________________ + + + + Is there anything about muds on WWW? + + The following is a list of LPMud related WWW URL's, a few of which + are even written in the mud programming language LPC: + + * http://www.bat.org + The BatMUD WWW Server + + * http://www.lostsouls.org + The Lost Souls WWW Server + + * http://www.imaginary.com + The Imaginary WWW Server + + * http://www.pvv.unit.no/viking + The Viking mud WWW Server + + + _________________________________________________________________ + + + + What are some mud related mailing lists? + + The following lists use the majordomo software. To subscribe, mail + majordomo at the sites mentioned with "subscribe list-name" in the + body of your mail. To get more information on the lists below, mail + majordomo at the site mentioned with "info list-name" in the body of + the mail. Naturally, list-name should be replaced with the appropriate + list name. + + For example, to subscribe to the lpc-language mailing list + lpc-language@imaginary.com, you do the following: + 1. mail majordomo@imaginary.com + 2. subject is irrelevant, body says "subscribe lpc-language" + 3. the list will then confirm you have been added by mail + + To mail a post to the mailing list, simply mail + lpc-language@imaginary.com and proceed as you would as if you were + mailing a single person. + + * amylaar-users@ibr.cs.tu-bs.de + The LPMud 3.2 and 3.2.1 Users Mailing List + + * foundation-mudlib@imaginary.com + The Foundation Object Library Mailing List + + * intermud@imaginary.com + The Intermud Protocols Mailing List + + * lima-mudlib@imaginary.com + The LIMA Mudlib Mailing List + + * lpc-language@imaginary.com + The LPC Language Mailing List + + * mudos-bugs@imaginary.com + The MudOS Bug Reporting List + + * mudos-patches@imaginary.com + The MudOS Patch Distribution List + + * nightmare-mudlib@imaginary.com + The Nightmare LPC Library Mailing List + + + + Individual muds may have their own mailing lists as well. Check with + your LPMud for details. For people running lists with an audience + beyond a single mud, please let me know of your list. If you use list + software not listed, I need the name of the list, how to subscribe, + and how to get more information. + _________________________________________________________________ + + + + Section II + + + + PLAYING LPMUDS + + Contents + 1. How do I play an LPMud? + 2. How do I get a list of LPMuds? + 3. Are all LPMuds in English? + 4. Ok, the mud is asking me for a name, what do I do? + 5. They told me I had to register! + 6. Name and password set, what next? + 7. I don't want anyone knowing my email address! + 8. Is it asking me for my gender? + 9. What does it mean by race? + 10. What is a class? What is a guild? + 11. I am in the mud, what do I do? + 12. What are some common commands? + 13. What is an alias? + 14. Why doesn't the mud save my equipment when I quit? + 15. Why is the mud admin ignoring me? + 16. The admins are being unfair, don't I have rights? + 17. What about freedom of speech? + 18. What else is there? + + + _________________________________________________________________ + + + + How do I play an LPMud? + + You must first find the internet address of the mud you wish to play. + Once you find the address, most often people use the "telnet" program + to connect to this address. The mud FAQ has an excellent section on + MUD clients, which are alternatives to the plain vanilla "telnet" + program. However, generally speaking, with "telnet", you can access + the mud of your choice by issuing the command: + + telnet address port + + For example (% is considered your prompt): + + % telnet nightmare.imaginary.com 1701 + % telnet 129.10.114.86 5555 + + And so on. Some telnet programs do not allow you to pass arguments at + the command line. Instead, you get something like this: + + % telnet + telnet> open + (to) nightmare.imaginary.com 1701 + + Once you succeed, you will get a welcoming screen which should say the + name of the LPMud and ask you for a name. A common error people will + make is leaving off the number at the end. If you do that, the telnet + program assumes you mean to go to port 23, and it will give you a + login prompt to the host machine. + + In addition, some VMS telnet programs use the following syntax: + + telnet 199.199.122.10/port=1701 + + + _________________________________________________________________ + + + + How do I get a list of LPMuds? + + I know of no place that lists ONLY LPMud's, however, there is Doran's + Mudlist, which is produced semi-regularly and lists muds by type. You + thus have all your LPMuds grouped together. You can find it posted to + rec.games.mud.announce. + + From the web, you can connect to these sites to get mudlists: + + * http://www.absi.com/mud/ + The mud Connector + + MUDs connected to the Intermud generally have mudlists which they + maintain dynamically based on which muds they are currently talking + to: + + * http://ie.imaginary.com:7885/gateways/mudlist + The Idea Exchange Dynamic Intermud Mudlist + + Keep in mind, however, these dynamic lists hold only LPMuds which + support intermud communication. They are by no means full lists. You + will also find that many muds on this list are in some sort of + developmental stage. + _________________________________________________________________ + + + + Are all LPMuds in English? + + No. To provide a list of such muds is beyond the scope of this FAQ. + Check the mudlists for a full and current listing. However, I would + like to know about other languages which might be supported in the + LPMud world, so please mail me if you have a mud in a language in + other than English, German, or Swedish. Known languages: + + * Chinese + + * Dutch + + * English + + * German + + * Swedish + + + _________________________________________________________________ + + + + Ok, the mud is asking me for a name, what do I do? + + Make up a name. Avoid using your real name or common names, real and + mythical. You want not only to give character to your persona, but you + also do not want everyone saying "Hey! Aren't you Bob from + JustAnotherMUD"? I chose the name Descartes, because I was a + philosophy major in college. In general, it is safe to assume any name + consisting only of more than two characters and less than ten (a to z) + is acceptable on any mud. Some muds allow really long names with + spaces, apostrophes, hyphens, and other marks. Others are in between + the extremes. Try the name you want. If the mud will not allow it, it + will tell you, and it should tell you why. + + After making up a name, one of two things will happen. Either you will + be prompted for a password, meaning you have picked a name someone + else is using, or it will ask you to create a password, meaning you + are a new character. If the first thing happens, just try again with + another name. If the second happens, you are in good shape. + + To create passwords, make up one different than the one you use to + access computers. Although muds encrypt passwords for storage, nothing + prevents an unscrupulous mud admin from intercepting that password and + using it for unethical purposes. It is also recommended that you use a + password with numbers and mixed upper and lower case letters in it. + _________________________________________________________________ + + + + They told me I had to register! + + Some muds require all their players to register before being allowed + to play. Also, it may be the case that someone from the same place as + you has been causing trouble, so the admins of the mud in question + have decided to require only people from that site to register. If + this is the case with the mud you wish to play, simply follow the + instructions they give. In most cases they will give you an email + address where you should send your registration. + + + _________________________________________________________________ + + + + Name and password set, what next? + + This is where you get to see why there is so little in common among + LPMuds from the player's point of view. Some LPMud's will ask you a + series of questions about who you are and what sort of character you + would like. Others ask nothing more. Among the questions you might be + asked are: what is your email address? what is your real name? what + gender would you like to play? what race would you like to be? what + class would you like to be? etc. + _________________________________________________________________ + + + + I don't want anyone knowing my email address! + + MUD Administrators have a legitimate need to know your email address. + No one else does. If a mud requires you to give your email address it + should either offer you the option of keeping it private, or it should + automatically keep the email private. If they do not keep your email + private and you desire privacy, do not play the mud. Do not complain, + however, that they ask for it. + + Note: + There seems to be some difference of opinion on this one, so I decided + to quote one of the comments: + + "Well, I have to disagree with this section: E-mail addresses are + very difficult to verify in bulk, and really not worth the trouble + unless you perform site registration. I believe the only people you + have a legitimate need for an email address from is your wizards. + Other than that, knowing the ip they log in from should be more than + sufficient." -Rust (John Viega) + + + _________________________________________________________________ + + + + Is it asking me for my gender? + + No. The game wants to know what gender you would like your character + to be. This means you can play a character of the opposite gender, + your own gender, or one of the alternate gender types which might be + offered. The other side of the coin to this, however, is that you + should never count on other people in real life being the gender of + the character they play. + _________________________________________________________________ + + + + What does it mean by race? + + Many LPMuds have a feature called character races. The term "race" in + these instances is not the same as the term used in modern society. In + fact, the LPMud term race would more correctly be referred to as + species. In fantasy type LPMuds, you will often see a selection of + "races" like human, orc, artrell, gnome, etc. When you are asked to + choose a race, a list of possible races should be provided for you. + _________________________________________________________________ + + + + What is a class? What is a guild? + + In general, a class is a grouping of players with common abilities. A + guild as well can be said to have the same definition. Many muds, if + they use either of these concepts at all, add some very individual + nuances. To muds which do not have classes or guilds, the concepts are + naturally irrelevant. Those which have one or the other are often + using the terms in an interchangeable fashion. Finally, those muds + which have both often define class in a more generic manner than + guild. For example, on Nightmare, a class is like a profession and the + guild like a particular job. You might have people in the fighter + class who are in the templars guild, and others who are in the rangers + guild. In short, the guild is a way of specializing your class + abilities. + + Other muds allow "multi-classing", which may mean joining multiple + guilds, classes, or both. It is always best to check out the "help + guild" and "help class" command on any given mud to see how it defines + these terms. + _________________________________________________________________ + + + + I am in the mud, what do I do? + + There is no one answer to this question, as the answer will vary from + MUD to mud. No matter what, however, you should see if the mud has a + "faq" command to get a listing of that mud's frequently asked + questions. In addition, you should learn how to use the "help" command + as well as find out about the rules governing that mud. + _________________________________________________________________ + + + + What are some common commands? + + The following commands exist on virtually all LPMuds. () around part + of a command indicate that that part is optional. [] indicates that + the text should not be taken literally. These commands naturally are + not likely to be found on non-English muds. + + * help ([topic]) + Gives you help. If you specify a topic, you get help on that + topic. If you just type help, you will either get help on where + to find other help, or you will be put into a help menu. + + * tell [player] [message] + Sends the string [message] to the player whose name is [player] + anywhere on the mud. Some LPMuds do not allow players to tell + to one another as it is viewed unrealistic. + + * say [message] + Sends [message] to everyone who is in the same mud room as you. + This command is almost always aliased to "'", such that "'hi!" + is the same thing as typing "say hi!". + + * who + Gives you a list of everyone connected to that mud. + + * look + Gives you a description of the mud room in which you are in. + + * look at [object] + Gives you a description of the object in question. + + + _________________________________________________________________ + + + + What is an alias? + + As with UNIX, most LPMuds provide some sort of method for creating + "aliases". An alias is simply a way in which you can have a easy to + type command represent another command. For example, you will often + want to type the phrase "get all from corpse" on any LPMud. It is much + easier to make an alias so that whenever you type "gac", the LPMud + interprets that as "get all from corpse". + + In order to create aliases, you need to know how your particular mud + handles aliasing. Older muds use a device called a quicktyper. Newer + MUDs have alias commands built in. Try issuing "help alias" and "help + quicktyper" commands in order to find out how aliases are handled on + your mud. If your mud uses quicktypers, you will have to go find the + quicktyper object before you can create aliases. Ask any other player + on such a mud where there quicktyper can be found. + _________________________________________________________________ + + + + Why doesn't the mud save my equipment when I quit? + + Balancing a mud so that everyone is not dripping in wealth and that + all players actually have a chance to die is hard work. It is nearly + impossible. One thing that makes it easier on balance admins is the + non-permanance of objects (in other words, objects do not save). For a + mud to save equipment, it requires a complete rethink of the way that + mud is balanced. + + It goes beyond the difficulty of balancing the mud however. There are + MUDs which do save equipment. The character of the game itself however + gets changed by what appears to be a simple change. Therefore asking + your mud admin, "can't you change the game so that it saves equipment" + is not so simple or limited as it might seem. To make such a change to + an existing mud would actually change that mud in such a way as it + would be unfamiliar to you. + + Putting it simply, saving equipment is not an impossible thing. + However, the consequences of doing so are way beyond what most players + are capable of realising unless they have been involved with muds + before. To do so on an existing mud would change it forever. Every now + and then, new muds appear with this feature. In fact, it is becoming + more and more common. Nevertheless, the concept foes have its + downsides. + _________________________________________________________________ + + + + Why is the mud admin ignoring me? + + Admins in particular are prone to a mud disease called "idling". This + means that the lights are on, but nobody is home. An idle person is + simply someone logged in to the game, but who is perhaps not actually + at their computer terminal. That person is thus not really ignoring + your question, since the person is never actually seeing it. + + If the admin is not idling, chances are that person is being + overwhelmed with questions or is actually coding online. Many LPMuds + will tell you that the person to whom you are talking is "idle" or + "editing". If you get that response to a tell, do not expect an answer + back right away. In addition, if it says the admin is editing (or + anyone else for that matter), then it is generally considered rude to + continue telling to that person as it makes it difficult for the + person to edit. + + Many people these days have the ability to be on several muds at the + same time. It is therefore entirely possible that the person to whom + you are trying to talk is in fact looking at another window. To get + that person's attention, it may be ok to "beep" them (by sending a + control-G in a say or tell). Some people do not like others to do this + to them, however, so be careful about doing it too much. + _________________________________________________________________ + + + + The admins are being unfair, don't I have rights? + + The short answer is yes, you have the right not to play the game. The + long answer is much more complex. First off, any reasonable set of + admins who wish to create a game which people will enjoy will + enumerate the sorts of behaviour you can expect from them. In other + words, admins on fun muds will state the rules of the game ahead of + time and will not deviate from those rules. That way you know what to + expect. In addition, if you do not like the rules, you don't get + involved with playing the game. + + What prevents an admin from breaking their own rules? Absolutely + nothing. In one sense, a mud is like someone else's swimming pool. You + have absolutely no right to swim there, and they have the right to + throw you out just because you talk funny or say things they don't + like. Fortunately, there are plenty of muds out there with civil + administrations to make this nothing more than a passing nuisance. + + A common misconception is that mud admins administrate muds for power, + and that arbitrary behaviour is a way of exercising that power. Though + there may be a few misguided individuals out there who do in fact + administrate muds for the sake of power, the fact is that no mud + administrator has any power over you. Remember, the worst thing any + admin can do to you is make you go play somewhere else. + + A final thing to remember is that muds evolve and rules evolve with + the mud. Just because rules change does not mean the admins are being + arbitrary. Arbitrariness is reflected in sometimes applying rules and + sometimes ignoring them, not in creating new rules to fit unforseen + situations. + + + _________________________________________________________________ + + + + What about freedom of speech? + + No, not even freedom of speech. Again, reasonable admins will clarify + in publically available rules what sort of speech (hate speech, + offensive language, or whatever) is not acceptable on that mud. You + may or may not agree with those rules or the political beliefs those + rules represent, but at least you do know where you stand on the mud. + It is thus up to you to decide if you can play under those rules or + not. In the event you encounter an unreasonable mud, there is nothing + much you can do but decide to leave. If it is a commercial mud, + however, deciding to leave can be some sort of leverage. + + A common source of friction between players and admins is where + players decide to criticize admins. Most often, the players are not + really trying to criticize the admins so much as inspire positive + changes to make a game they love even better. In those cases, it is + always good to remember that the admin is a real human who is closely + involved with what the mud is. If you keep that in mind, you can often + help bring positive changes to the mud you play without + unintentionally striking a hidden chord in a sensitive admin. + + + _________________________________________________________________ + + + + What else is there? + + Explore the mud! Most gaming muds have places called "newbie" areas + which are simplistic places for people new to the game to go and get + the hang of things. When you first log in to a new mud, you should ask + the others where the newbie area is. Also, read the login screen and + news which scrolls across your screen at login time, as they contain + important information about characteristics unique to the mud you are + playing. + + Ask people questions. Just make sure you have read the help files + first, or you will be sure to annoy someone. In addition, try not to + choose a single person for your queries. Constantly being asked + questions by the same person can often annoy people as easily as + stupid questions. + _________________________________________________________________ + + + + Section III + + + + CODING ON AN LPMUD + + Contents + 1. What is coding? + 2. What is LPC? + 3. How do I get to code on an LPMud? + 4. How do I learn to code? + 5. What is The Idea Exchange? + 6. How do I learn to code a room/monster/weapon/armou...? + 7. But you said that all LPMuds use LPC! + 8. My code is not working! How do I fix it? + 9. What is an efun? an lfun? a kfun? a sefun?... + 10. Can I take my area from LPMud X to LPMud Y? + 11. Can I code offline? + 12. Why does the mud use ed? Why not have the mud use vi/emacs...? + 13. How do I put my code into the game? + + + _________________________________________________________________ + + + + What is coding? + + Coding is writing files for the computer to read. In the case of + LPMuds, this means writing files in a computer language called LPC. + The LPMud server reads these files and interprets what those files are + telling the computer to do when certain player actions occur. Often + that means things like displaying a description of a room when you + enter it and so on. The LPC files which make up the backbone of any + mud are called the mudlib. Coders use the mudlib code in such a way as + not to have to rewrite many of the most common instructions over and + over again. With most good mudlibs, therefore, there is more creation + involved than coding. + _________________________________________________________________ + + + + What is LPC? + + LPC is an object building language created by the author of the + original LPMud server, standing for Lars Pensjö C. Structurally, it is + much like the more popular programming language C. Designed with LPMud + object building specifically in mind, it puts the power of game + building in the hand of the general user. + _________________________________________________________________ + + + + How do I get to code on an LPMud? + + Policies vary from mud to mud. Some muds require you to make a + certain player level before being allowed to code. Others require you + to pass a test or fillout an application. Still others just let anyone + come on and code. If you really want to get in on things, the best + thing to do is either to talk to the admins of the mud you are + playing, or go to The Idea Exchange (ie.imaginary.com 7890) The Idea + Exchange has a newsgroup for coders looking to code and another for + muds looking for coders. Keep in mind that many muds which are open to + players already have more coders than they need. + _________________________________________________________________ + + + + How do I learn to code? + + There are two parts to learning how to code on your mud: + 1. Learning LPC + 2. Learning your mud's object library (mudlib) + + Each mud should have detailed documentation on part 2. Two LPC + textbooks, a beginner and an intermediate, exist to take care of part + 1. You can get the textbooks via ftp at + ftp://ftp.imaginary.com/pub/LPC/doc. Documentation, however, will + not really do anything without looking at examples, practicing, and + talking to more experienced coders. Examples should be everywhere on + your mud (though they are not necessarily good examples). Practicing + is simply just copying code you do not understand, making small + changes to it to see what they do, and learning from what happens. To + learn more about how to code from others, talk to more experienced + coders on your own mud or visit The Idea Exchange which is designed to + help people learn LPC. + _________________________________________________________________ + + + + What is The Idea Exchange? + + The Idea Exchange is centered around the advancement of LPMud + technology and the promotion of its use. On The Idea Exchange you will + find many of the people responsible for the software commonly used to + build LPMud environments, including the authors of drivers and + mudlibs. It is an excellent place for learning about LPC and + discussing new ideas. + _________________________________________________________________ + + + + How do I code a monster/room/weapon/armour...? + + Read your mud's documentation, as this varies greatly from mud to + mud. + + "Also, questions like that are almost impossible to answer in any + other way than showing an example. Thus, a much better question is: + 'Where can I find an example of how to create a XXX?' or 'I don't + quite understand this part of the example on how to...'" -Drevreck + (Lars Syrstad) + + + _________________________________________________________________ + + + + But you said all LPMuds use LPC! + + Yes, they do. However, they do not all use the same mudlib. The + mudlib is the basic LPC files you make use of then you write your LPC + files. The LPMud server in turn interprets your files and stores them + in memory. Two muds using different mudlibs therefore can be wildly + different from one another. And since the mudlibs are so different, + the files you will write will be equally different. + + An analogy might be that of a human dialect. Quebecois French and + Continental French often use different words and such in order to + express ideas. In spite of this, the language structure is the same. + So, both are still French even though you sometimes need to say + different things in order to mean the same thing. + + In writing an object in LPC, you are almost always using the mudlib's + LPC files rather than totally writing files from scratch. You do this + through something called inheritances. Inherited code which exists on + one mud may not exist on your mud, or may exist differently. Therefore + when you try to use that code, it will not work as you expect even + though both are in LPC. + _________________________________________________________________ + + + + My code is not working! How do I fix it? + + First, determine if the problem is with... + * the object failing to load + * the code causing an error when it runs + * no errors, it is just the expected things do not happen + + Now that you know what "type" of error you have, you need to isolate + it. Isolating it depends on the type of bug... + + the object fails to load + You have the bug isolated for you you in your error file. The + location of the error log depends on the file name of the + object with the error. It also depends on the way your mudlib + logs such errors. Nightmare, for example, logs compile errors + to /log/errors/std for obejcts in /std, etc, and + /log/errors/descartes for objects from /realms/descartes. TMI-2 + would log my errors to /u/d/descartes/log. I am not sure where + they put mudlib errors. I know with MudOSthe driver does + isolate the error for you to a useful degree of certainty. More + on this later. + For LPMud 3.2.1, you can use the: #pragma verbose_errors + preprocessor directive to make compile time errors include a + bit of context in error messages. Some mudlibs turn this + #pragma on by default. + + an error occurs during execution + These are logged in the mud's runtime error logged, and they + ALWAYS reflect the exact line where something happened. On + MudOS muds before 0.9.20, the system runtime log was + /log/debug.log. The mudlib in later versions has the option of + naming it whatever. + + "Brought over from LPMud 3.[01].x , LPMud 3.2 uses + /`hostname`/debug.log. LPMud 3.2.1 allows you to pass the option + --debug_file to change this default. If there is a triple fault + (i.e. an error while the master was processing an error in error + processing), and you compiled the driver with the TRACE_CODE option, + there will also be a trace of the last instructions executed. + Moreover, if the driver is not out of memory, and there is no triple + fault, the apply runtime_error() is called in the master, with the + error message, file name, object name and line number as arguments." + -Amylaar + + Note that for drivers which can compile LPC code to C and then link it + into the driver, no line number information will exist to help + you in debugging. You should therefore debug your LPC code + thoroughly before compiling it to C. + + no errors, you just do not get expected results + These are the hardest to debug. You need to go through the code + and test + + 1. Which code is being executed + 2. The values of the variables in the executed code + + How do you do this? Take the following code with a priveledges bug... + + + /* from /cmds/adm/_rid.c */ + + int cmd_rid(string str) { + if(!archp(previous_object())) return 0; + if(!str || !user_exists(str = lower_case(str))) return 0; + if(!((int)USERS_D->rid_user(str))) return 0; + message("system", "You rid "+capitalize(str)+".", previous_object()); + return 1; + } + + /* EOF */ + + /* /secure/daemon/users.c */ + + int rid_user(string str) { + return rm(DIR_USERS+"/"+str[0..0]+"/"+str+SAVE_EXTENSION); + } + + /* OTHER CODE DELETED FOR BREVITY */ + + This is not real code (as a lot more should exist in such an + operation). However it does serve the point. This code will + load fine and execute without error. However, it will not + delete the save file of any user. If anyone executes it, the + following will happen: + + + > rid weenieplayer + What? + > + + So what do you know? You know you typed "rid weenieplayer", and you + know you got 0 returned. One of the following things happened: + + 1. The "rid" command never got executed + 2. The archp() returned false for the person executing the + command + 3. For some reason, str was equal to 0 + 4. rid_user() in users.c returned 0 to the command + + How do you know if 1 is the problem? put the line... write("rid + command executed") as the first line of the cmd_rid() function + in the rid command. If the rid command is executed, you will + see that it is executed before you see "What?". If it is not, + you will just see "What?". If you do not see that line in + write(), then you know your bug is with you whatever calls the + "rid" command. If you do, then you know you must proceed + further. + + Do the same after each line which returns 0. Make sure each write() + string is unique so you know *which* line is being written out. This + will tell you exactly *which* line is returning 0 in the rid command. + + In this case, it is #4 which is the problem. The users daemon is + returning 0 for for rid_user(). This means that rm() is definitely + returning 0. rm() only returns 0 when an rm fails. rm() only fails + when an object does not have proper access. Therefore, in this case, + you need to fix the bug in your security. + + If for some reason you cannot go editing the files in question (i.e. + they are in the base lib files to which you have no access, changing + them would be even more troublesome, etc), you should consider the + efuns trace() and traceprefix(). + + Do you need to go through all of these tedious steps? No, you can + generally make good guesses as to where to look the more familiar you + become with the code. For example, in this case you pretty much could + have elimited step 1 if that command is an old command which used to + work. After all, it is highly unlikely that the mud would suddenly + stop executing that one command! + + Furthermore, if you had just made a change to the security system, you + would immediately suspect that rm() failed and thus would have checked + that first. + + This is why presenting me with your entier rid command would have been + useless to me. I would have looked at it and said it *looks* ok. But I + have no idea what changes you have recently made to your mud, nor do I + know from looking at the code which of those lines is returning 0. I + can only basically tell you that one of those lines is failing. + + However, if you were to tell me that for some reason your user object + was returning 0 in trying to rm() the user file during the rid + command, I could tell you details about the relevant parts of the + Nightmare LPC Library security to this daemon. And then you could + use that information to debug further and ultimately fix the bug. + _________________________________________________________________ + + + + What is an efun? an lfun? a kfun? an sefun?... + + For any function in LPC, there are three distinct parts... + 1. the prototype + 2. the call + 3. the definition + + Whate differentiates all of these different types of functions is + where they are defined. The definition of the function is the part + which says what it does. + + afun (auto function, DGD only) + the function is defined in the auto object and behaves like and + efun from other drivers. This function is really very special + type of lfun. + + apply + a function defined in the mudlib designed to be called only by + the driver. All applies are also lfuns. Most of the functions + in the DGD's driver object and other's master object are + applies. In addition, the functions create(), init(), and + reset() are also applies for LPMud 3.2 (not 3.2.1), MudOS, CD, + and Urimud. + + efun (external function) + this type of function is defined external with respect to the + mudlib. In other words, in the driver. Since it is defined + inside the driver, it is faster, but the mudlib is left with + little control over what it does. + + kfun (kernel function, DGD only) + This type of function is much like an efun in that it is + defined external to the mudlib in the driver kernel. There are + some ways beyond the scope of this FAQ in which kfuns differ + from efuns, ways which have little bearing to daily coding. + + lfun (local function) + Any function defined inside an object in the mudlib. The + functions you write (like create() or reset()) are lfuns. + + sefun (simulated external function) + lfuns defined in an object known as the simul efun object. Any + object in the mudlib is allowed to use these functions as if + they were efuns (treat them like local calls). + + You might also want to keep in mind the difference between a local + call and a call_other. A local call is a call to a function defined in + your object or to one of the objects it inherits. A call other is a + call to a function defined in another object. Efuns and simul efuns, + though not defined in your object, act like local calls. Afuns and + kfuns are in fact local calls, since all objects inherit the auto + object to which they are local. + _________________________________________________________________ + + + + Can I take my area from LPMud X to LPMud Y? + + Can you? If they use the same mudlib, yes. May you? Often muds have + restrictions against importing code in order to keep the mud unique. + Talk to the administration of both muds for local details. + _________________________________________________________________ + + + + Can I code offline? + + There are many different methods of coding offline, and which one is + available to you depends on your mud. The methods are: + 1. CreRemote + 2. ange-ftp + 3. wizshell + 4. your favourite editor + ftp + 5. cut-and-paste + + Editing offline allows you a faster response time, the ability to + multitask, and the ability not to be bothered by incoming tells + screwing up your edit window. It also allows you to make use of + editing environments which may be much more robust than standard mud + ed. + + CreRemote has both UNIX and Windows versions. This program basically + allows you to edit files on your mud as if they were on your local + machine. You do not have to mess with transferring files, and you can + do things like update the files to see if they load. CreRemote for + UNIX requires: + * any kind of UNIX + * perl 5 or later + * a direct internet connection using TCP/IP + * an RCP server on the host mud + + CreRemote for Windows requires: + * Windows 3.1, Windows 3.11, Win-OS2, Windows NT, or Windows 95 + * Winsock support + * an RCP server on the host mud + + ange-ftp is an emacs mode which allows you to edit files in emacs and + have them automatically ftp'ed to your mud and back. ange-ftp + requires: + * emacs with ange-ftp mode + * an FTP server which gives access to host mud files + + Wizshell is basically a UNIX program which gives your coders limited + access to a UNIX shell. This will not allow access to emacs, since + there is no version of emacs which is secure enough for such a limited + shell. wizshell requires: + * wizshell from ftp://shsibm.shh.fi/pub/Wizshell + * UNIX + + Using a local editor and ftp allows you free choice of which editors + you use, but you have to manually transfer each file. If going from a + DOS environment, you also need to watch for carriage-return/line-feed + translation. FTP requires: + * An FTP server which gives you access to your mud files + + Cut and paste requires no file transfer and allows you to use any + editor which has immediate access to your mud files. For example, you + can edit on your home computer using Notepad, then cut that from + Notepad and paste to your mud window which is likely in ed. Cut and + paste requires: + * The ability to cut and paste from editor to mud window. + + + _________________________________________________________________ + + Why does the mud use ed? Why not have the mud use vi/emacs...? + + See Section IV: How do I get my mud to use vi/emacs instead of ed? + _________________________________________________________________ + + + + How do I put my code into the game? + + A file is considered "in the game" if another file already visible to + players references it. So, to put your stuff in the game, you need to + change code already in the game to reference your code. This action + normally requires the action of mud administrator. Most muds have some + sort of quality control policies which state rules for having your + code reviewed. + _________________________________________________________________ + + + + Section IV + + + + STARTING YOUR OWN LPMUD + + Contents + 1. How do I start my own LPMud? + 2. How do I find a site? + 3. Can I charge players to play my mud? + 4. Why can't I use any of the other servers or mudlibs? + 5. Our system needs upgrading, can't I get donations? + 6. I have a site, now how do I choose a server/library? + 7. Where can I find all this stuff? + 8. Help! I can't get my driver to compile, what should I do? + 9. I have applied patch XXX, and now nothing works any more + 10. How do I do ANSI colours? + 11. Why not just hard code the colours? + 12. How to I make the mud use vi/emacs instead of ed? + 13. Is it possible to connect multiple muds together? + 14. Can a mud server run on DOS? + 15. Can a mud run under AmigaOS? OS2? Windows NT? etc...? + + + _________________________________________________________________ + + + + How do I start my own LPMud? + + + 1. Come up with a unique and interesting idea + 2. Find a site + 3. And do: + 1. Choose a server + 2. Choose an object library + Or: + 1. Choose an object library + 2. Choose a server + Or: + 1. Choose a server + 2. Write your own object library + Or: + 1. Write your own server + 2. Write your own object library + 4. Define administrative policies + 5. Find people to code areas for the mud + 6. Get some areas completed + 7. Open to players (with a beta test stage recommended + + + _________________________________________________________________ + + + + How do I find a site? + + The most common method is to talk to the administrator of the machine + from which you access muds and the rest of the Internet. If the + resources are available, they will often allow you to run your mud + server unless something political like a no-games policy is preventing + it. If you are not running a mud as a game, however, this is not + relevant. + + Never run a mud without talking to your system administrator. LPMuds + take up a lot of system resources, and many places simply cannot spare + those resources on a single project, especially if the project is + non-essential to the functioning of the entity running the machine. + Not only is it just plain wrong to run a mud without permission, it + also predisposes sysadmins to saying no to people who ask them when + the resources are free. + + If you cannot run it on your local machine, post a note to the + ie.sites.wanted newsgroup on The Idea Exchange. Do not post to USENET + newsgroups unless you have a working mud. It does not need to be + complete, but posting notes saying "I have a cool idea, will someone + give me a site" is inappropriate, unless that idea is completely + fleshed out with some sweat in the form of work on paper and such. + + Another avenue of finding a site is talking to local internet access + providers. Often, they have extra small machines on which a mud could + be run (sometimes for a fee). The most expensive route is to buy your + own machine and your own Internet hookup. + _________________________________________________________________ + + + + Can I charge players to play my mud? + + If you write the server from scratch AND you wrote your mudlib from + scratch and you have agreements with the coders who wrote areas on + your mud, the answer, of course, is yes. The above will take roughly + 3-5 years of full-time work to accomplish as well. + + If you do not wish to go through all of that time to write your own + server and object library, then you may only choose from DGD or MudOS + as your server. For both servers, you will need to get express + permission from their copyright holders, Dworkin for DGD and Beek for + MudOS. For DGD, the only object library you may use for such + purposes is LPMoo. Only Nightmare and Foundation may be licensed for + MudOS. + _________________________________________________________________ + + + + Why can't I use any of the other servers or mudlibs? + + They all come with some variation of the same copyright. Since all + drivers except DGD were derived from LPMud 3.0, they all require a + copyright at least as strict as that one, which basically states that + you can use the server as you like, so long as you do not make a + profit off of its use. Most current servers have much more strict and + explicitly copyrights. On top of that, many of the mudlibs which exist + also have similar copyrights. To require money of your players is + therefore a violation of international copyright laws. Although MudOS + was originally derived from LPMud 3.0, Lars has recently suggested + modifying the LPMud 3.0 copyright and has specifically given the + developers of that server the right to work under a modified copyright + given the degree to which MudOS has changed since LPMud 3.0. + _________________________________________________________________ + + + + Our system needs upgrading, can't I get donations? + + Yes, you can request that your players donate money as long as the + end of that money is to run the mud and donations are not a + prerequisite for play on the mud. In other words, they must be + donations, not fees. + + Note: + I am not a lawyer, nor am I the author of all the mud code out + there... Therefore, keep in mind that what I am saying about + copyrights is my interpretation and not binding upon ANY of the server + or mudlib authors out there. For reference to what is binding with + respect to my code, see the copyright notice which accompanies it. + _________________________________________________________________ + + + + I have a site, now how do I choose a server/library? + + Some people have a favourite mudlib, and therefore go at building + their own mud from the angle of using that mudlib. Others have a + favourite server and start from that angle. Others simply want to + start a mud fast, while others want to really tinker with it and make + it their own. The following is a rough guide to what is out there: + + Note: + Also, I only publish software which the authors have somehow made + known to me to be available, or in fact are widely known to be + available. I will not publish information about software which I have + no such verification, since being on a public ftp site is not the same + as being publically available. + + Servers + + CD + Generally considered a slow driver, however it is designed to + work very closely with the CD-lib. Therefore tests showing the + CD driver to be slower are not necessrily fair as sole factors + since they are mudlib-independent tests. The CD-lib is + considered a well designed lib which is often a factor which + leads people to choose this server. To see a CD server mud, + visit Genesis. + + DGD + DGD is built on the belief that small is good. This is absent + of much of the extra baggage which exists in all other drivers + since it was created from scratch. There currently exist two + native mudlibs for DGD, one of which is a MOO simulation. DGD's + documentation is sparse. It does support compile time LPC->C + compiling, meaning that when you compile the driver you can + have some of your LPC files converted to C and compiled with + the driver. In addition, unlike other LPMud servers, it is + disk-based, meaning you can run a huge mud on virtually no RAM. + You therefore never need to reboot or save objects. Dark has + written intermud support for DGD which can be gotten separately + from the driver. + + LPC4 + Maintained by Profezzorn, it supports a scripting feature that + allows you to execute LPC files as atomic programs without + running the mud in the traditional sense. In addition it + features lambda closure types which are actually understandable + to most people. It is designed for speed through the philosophy + of creating large numbers of efuns to perform CPU intensive + work. I know of no muds using this driver in practice. LPC4 + also has socket efuns with TCP support. + + LPMud + Once the fastest of all the drivers, it has lost this crown to + MudOS. Nevertheless, it is an extremely fast driver which + supports the old LPMud 2.4.5 Mudlib. It also supports closures, + though its closure syntax is beyond general ease of + comprehension. There is only one mudlib in wide release which + is native to this server. + + MudOS + The fastest and most feature-filled of the LPMud drivers, this + one comes with TCP support for mudlib objects allowing you + things like WWW, finger, SMTP, USENET, and other such access to + Internet resources from inside the mud. It also comes with a + choice of well-developed mudlibs native to the server. MudOS + allows you to choose between UID support and no-UID support, + which makes it easy to hack a LPMud 2.4.5 mud to work with + MudOS if that is your cup of tea. MudOS supports a new function + pointer syntax which is as functional as LPMud's closures + without LPMud's obscure closure syntax. + + Shattered World + Developed by one of the original LPMuds. I believe this driver + originated from one of the first LPMud releases and has been + heavily customized in such a way as not to be recognizable as + such. + + Urimud + Urimud is descended directly from LPMud 2.4.5, as opposed to + the other LPMud's (except DGD, which is created from scratch), + which are all descended from LPMud 3.0. Its most prominent + feature is that it can handle running multiple muds on a single + process. + + Object Libraries + + CD-lib + I am told this is a very well-designed mudlib. Some features of + it are an enhanced sense of reality through player recognition + (you must make the acquaintance of players before knowing who + they are) and UDP intermud communications. + Runs under: CD (native) + + Discworld + Advanced command parsing system and user interface, as well as + many concepts you will not see in other mudlibs for any server. + Too many frogs and wombles. + Runs under: MudOS 0.9.20 (native) + + Foundation IIr1 + A basic mudlib with nothing extra for people who want a solid + design base from which to design a unique mudlib. No combat or + anything else fancy is included. Nothing about it is + pre-disposed towards fantasy or even game playing for that + matter. On the positive side, there is nothing to deconstruct + in order to build your own mudlib and there is more of a solid + base to work from than something like Lil. The downside is that + you will have to put in a lot of work to make a playable game + from this. + Runs under: MudOS v21.5 (native) + + Heaven 7 + Runs in both compat and native modes with autoconfiguration for + whichever driver you are chosing. Since it runs under 2 + different drivers, you have the advantage of portability. + Security under native mode is questionable, and it does not + take full advantage of any one driver. It also advances very + little beyond LPMud 2.4.5. + Runs under: LPMud 3.1.2 (native), LPMud 3.2 (non-native) + + Lil + A small, essentials only mudlib. Designed basically to give you + examples of files as they must minimally be for the MudOS + driver to run. Only useful if you plan really to write + something totally from scratch. + Runs under: MudOS (native) + + LIMA 0.9r6 pre-alpha + This is a brand new library, featuring the new MudOS natural + language parsing package and a UNIX-like wizard shell with + output redirection and command piping. In addition, it is a + very modular, object-oriented mudlib with stack-based security. + As the name suggests, this mudlib is 'pre-alpha', meaning + documentation is sparse and some bugs are known to exist in the + mudlib. + + Runs under: MudOS v22a3 (native) + + LPMoo + A MOO simulation using LPC. This library allows you to work and + play exactly as if you were using MOO instead of LPC. + Runs under: DGD (native) + + LPMud 2.4.5 + The most well-known mudlib in existence. It is rather simple, + not the best design, but if you know it, it is useful. Also, + the widest range of drivers support it. Good for putting up and + running a mud quickly. It is very ancient and inferior in + design, flexibility, and functionality to modern mudlibs. + Runs under: DGD (non-native), LPMud 3.2 (non-native), LPC4 + (non-native) + + Melville + Extremely minimalist mudlib for DGD. Documentation is sparse + and it has few features. + Runs under: DGD (native) + + Nightmare IVr2.1 + Nightmare IV is a complete rewrite of the Nightmare Mudlib from + scratch, using Foundation II as a base. It has a highly object + oriented design which makes it easy to customize, + multi-classing, limb-oriented combat, and a stack-based + security system which addresses the flaws of UID-based + security. In addition, it uses the MudOS natural language + parsing package. This release is an alpha release, meaning that + some documentation is lacking and known bugs do exist. + Runs under: MudOS v22a6 (native) + + Shattered World + Mudlib to go with the Shattered World driver. It supposedly has + a system for doing detailed economic and predictive analysis. + Other than that, I know absolutely nothing about it. + Runs under: Shattered World (native) + + TMI-2 1.2 + Generic, designed for those who want to tinker around with + their mudlib rather than get a mud up in no-time flat. Designed + to be easily modified and comes with a full-range of intermud + support as well WWW support. Features include the ability to + take over monster bodies. Downside is its poor design and + performance. + Runs under: MudOS v21 (native) + + TubMUD + Very intricate, and, according to Rust, "it is beautiful if you + can figure it out." Intended more for Tub wizards to run at + home than for wide-release. + Runs under: LPMud 3.2 (native) + + If I have missed a lib, or stated something incorrect about your + server or mudlib, or simply ommitted something, don't go flaming me. + Email me the correct information so I can include it in the FAQ. I did + my best to be fair in this, but in simply undertaking this task I have + opened myself up to flames from anyone who I might have gotten wrong + or simply does not like what I said. So please be gentle, and + understand I mean no malice or ill-will anywhere in there! + _________________________________________________________________ + + + + Where can I find all this stuff? + + These first set of sites are generic "goto" sites when looking for + LPMud stuff: + + * ftp.actlab.utexas.edu + + * ftp.bat.org + + * ftp.ccs.neu.edu + + * ftp.imaginary.com + + * ftp.lysator.liu.se + + In addition, the primary site for individual pieces of software: + + * CD (server and library) + ftp://ftp.cd.chalmers.se/pub/lpmud/cdlib + + * DGD (server) + ftp://ftp.lysator.liu.se/pub/lpmud/drivers/dgd + + * Discworld (library) + ftp://ftp.imaginary.com/pub/LPC/lib/Discworld + + * Foundation (library) + ftp://ftp.imaginary.com/pub/LPC/lib/Foundation + + * Heaven 7 (library) + ftp://ftp.ccs.neu.edu/ + + * Lil (library) + ftp://ftp.actlab.utexas.edu + + * LIMA (library) + ftp://ftp.imaginary.com/pub/LPC/lib/LIMA + + * LPC4 (server) + ftp://ftp.lysator.liu.se/pub/lpmud/drivers/profezzorn + + * LPMud 2.4.5 (library) + ftp://ftp.lysator.liu.se + + * LPMoo (library) + ftp://ftp.ccs.neu.edu/pub/mud/mudlibs/lpmoo + + * LPMud 3.2 (server) + ftp://ftp.ibr.cs.tu-bs.de/pub/games/lpmud + + * Melville (library) + ftp://ftp.ccs.neu.edu + + * MudOS (server) + ftp://ftp.imaginary.com/pub/LPC/servers/MudOS + + * Nightmare (library) + ftp://ftp.imaginary.com/pub/LPC/lib/Nightmare + + * Shattered World (server) + ftp://moo.cs.rmit.edu.au/pub/xlpc + + * TMI-2 (library) + ftp://ftp.ccs.neu.edu + + * Urimud (server) + ftp://ftp.netcom.com/pub/urimud + + + _________________________________________________________________ + + + + Help! I can't get my driver to compile, what should I do? + + Thanks to Rust for putting together an answer for this question. + + First of all, learn how to redirect stderror to a file if you don't + already know how, or at least find a computer where you can cut and + paste. Then, you have 3 options for getting these errors to a more + experienced driver person: + + * You can try The Idea Exchange a mud dedicated to mud + development, where people who may be able to solve your + problem, or at the very least you can post it to your target + driver's newsgroup on The Idea Exchange, where they will be + seen by knowlegeable people fairly quickly. In addition, for + Lima specific compile problems, you can visit its support + site Lima Bean (telnet://lima.imaginary.com:7878). + + * You can post it to rec.games.mud.lp, but don't cross post, and + it probably wastes a lot more bandwidth on this newsgroup than + on The Idea Exchange. + + * You can mail the maintainers of your driver: + + + CD: jacob@dd.chalmers.se + + LPC4: hubbe@lysator.liu.se + + LPMud 3.2: amylaar@meolyon.hanse.de + + MudOS: tim@handel.princeton.edu + + Urimud: urimud@netcom.com + + For MudOS or DGD help, you are most likely to get a timely response by + posting to the proper newsgroup on The Idea Exchange (ie.imaginary.com + 7890). For LPC4, your best bet is direct mail, for CD, either direct + mail or visiting Genesis (hamal2.cs.chalmers.se 3011) and mailing + Tintin et al. + _________________________________________________________________ + + + + I have applied patch XXX, and now nothing works any more. + + Answer from Joern Rennecke (Amylaar) + Have you supplied the proper -p option to patch? If not, you might end + up with a patch applied to the wrong file. Check with the appropriate + man page to "patch" for more details. + _________________________________________________________________ + + + + How do I do ANSI colours? + + There are several misconceptions about colours. The first + misconception is that all of the world is an IBM PC using ANSI style + colours. In fact, there are many different sets of escape sequences + which have the same effects depending on terminal emulation. If your + goal is providing colour support to players, then limiting yourself to + just ANSI support is very similar to saying "Only people with IBM + compat's can play my mud." Well, maybe not quite that drastic, but you + get the point. + + Also, you should keep in mind that the term ANSI has nothing to do + with colours. ANSI is a standards organization, and one of the zillion + things for which they have standards is escape sequences and what they + do. Keep in mind that your goal is to have colours. + + Finally, about giving your mud colour support. The Discworld Mudlib + has developed a protocol now supported by at least Foundation, + Nightmare, and TMI-2. There is no reason, however, that other libs + cannot add support this protocol. It enables creators to code to a + single set of codes and have those codes dynamically interpreted into + colours proper to the terminal emulation being used by a given player. + If a certain player has no colour support, that person does not see + the colour codes. For more information on this protocol, stop by The + Idea Exchange at ie.imaginary.com 7890. + _________________________________________________________________ + + + + Why not just hard code the colours? + + There are multiple colour escape sequence protocols. Some players + cannot support colour escape sequences at all. Sending colour escape + sequences to people who cannot handle them, or to people who use + different protocols can mess up their displays severely, making the + game unplayable. + _________________________________________________________________ + + + + How to I make the mud use vi/emacs instead of ed? + + This question gets asked constantly. When you come around to ask it, + think about what exactly you want. Do you want to have vi or emacs on + your mud? Or is it that you really want to have a convenient way of + editing mud files (which ed certainly is not)? In truth, the real + problem is the need for something more convenient than the very + inconvenient ed which muds use. The kneejerk response to this need is + the belief that your UNIX editing tools will solve this need. The fact + is, however, there are better ways to accomplish this goal which are + listed in Section III: Can I code offline? + + Not convinced? There are the technical reasons that people often give, + such as the fact that any visual editor will require character mode, + which is non-trivial in the current batch of muds and very network + intensive. The bottom line as to why this is not generally done is + that it provides nothing, yet costs a lot. + _________________________________________________________________ + + + + Is it possible to connect multiple muds together? + + Is it possible? Yes. + + Why do you want to connect muds? There are two common meanings behind + this: + 1. Distributed mudding + 2. Connecting multiple muds + + Distributed mudding is basically a single mud whose resources are + spread across multiple servers. Distributed anything is generally + required of resource intensive, mission-critical applications. muds + are not, in the scheme of things, resource intensive and they + generally are not mission-critical applications. Distributed computing + basically gives you the ability to expand horizontally rather than + vertically. That means instead of buying yourself a sparc 20 to run + your mud, you can architect it in such a way that two sparc 2 + computers will give the same performance. + + The fact of the matter, however, is that no mud currently in existence + uses the resources which require this kind of scalability. In + addition, most MUDs have a hard enough time finding one site, much + less getting two. + + More commonly, however, people are thinking of the ability to connect + multiple MUDs together. Before deciding this is a good thing, you + should define the problem you want solved by connecting muds. As of + yet, I have not heard a problem which connecting muds solves. The most + vocal reason is to allow a person to have the same character across + multiple muds. At that point, however, you have to define what it is + to be that person. Most people will quickly say that what defines + their character is that they control it. If that is the case, then + connecting muds does not solve this problem. A client which allows the + person to login to multiple muds is what solves this problem. + + The response then might be to have the same level/skills/whatever + across the multiple muds. At this point, however, they cease to be + multiple muds connected, but instead one huge distributed mud. This + would be a poor way to design a distributed mud, and would also lead + to political headaches and a huge waste of creative talent. + _________________________________________________________________ + + + + Can a mud server run on DOS? + + Yes, most of the servers have DOS binaries available. In addition, + most of the mudlibs have had their files arranged and ported so they + fir in the FAT 8.3 naming scheme. If you wish to allow others access + to the mud over modem lines, be sure to get the comdrv17.com file with + your server and mudlib. For those who choose mudlibs with colours in + them, the current batch of drivers was compiled in such a way that the + drivers do not send output through ANSI.SYS (thus no colour). + _________________________________________________________________ + + + + Can a mud run under AmigaOS? OS/2? Windows NT? etc...? + + These are the ports of which I am aware: + + AmigaOS + DGD, LPMud 3.2, 3.2.1, MudOS + + Atari + DGD, LPMud 3.2, 3.2.1 + + System 6 + MacMUD (which is LPMud 3.1.2) + + MacOS + MacMUD, DGD + + OS/2 + LPMud 3.2, 3.2.1, MudOS + + Windows 95 + MudOS + + Windows NT + MudOS + + + _________________________________________________________________ + + Credits + + Credits for information in this FAQ beyond the information provided by + the author: + + Abigail, Stig Bakken, Jose Corrales, Felix Croes, Joshua P. Dady, Lars + Duening, Paul Gregg, Monique Girgis, Pelle Johansson, Andru Luvisi, + Joern Rennecke, Danne A Solli, Christina Sterman-Hack, Lars Syrstad, + Pekka Timonen, Linus Tolke, John Viega, Petri Virkkula + _________________________________________________________________ + + Copyright (c) 1994-1995 George Reese + This document may not be reproduced outside of USENET newsgroups, ftp + archives, electronic mailings, and other similar not for-profit + endeavors without the express written consent of George Reese. + _________________________________________________________________ + + This FAQ is maintained by George Reese, borg@imaginary.com diff -c -r --new-file ds1.1/lib/doc/guide/chapter01 ds2.1/lib/doc/guide/chapter01 *** ds1.1/lib/doc/guide/chapter01 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter01 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,36 ---- + chapter 1 "Introduction" + + If you're reading this, you've probably been + successful in installing Dead Souls, and are able + to get around and manipulate stuff within it. + + There are lots of questions that new admins + have at this point. This book is not intended to + answer them. Specific questions about administration + are handled in the Admin FAQ, which you can read + at http://dead-souls.net/ds-admin-faq.html . A + local copy is archived in the /www directory, but + this may be out of date by now, and you'd be best + served by looking at the online version. + + This guidebook isn't about "how to" or "where + is," although such issues may be handled incidentally. + The point of this guidebook is to describe to you + various principles that are important to your + success as a Dead Souls mud admin. + + The tone of these chapters is intended to be + conversational. Because of this, it may sound like + I'm being condescending (that means "talking down + to you"), but that isn't intentional. I'm + assuming that you fully understand I'm not the boss + of you, that you can decide for yourself what is + best for your mud, and that the contents of this + guidebook are thoroughly biased. + + However rambling these pages might be, know that + I claim no authority over What Should Be. I can only + tell you, from my experience, how things look, and + how I *think* things work best. + + diff -c -r --new-file ds1.1/lib/doc/guide/chapter02 ds2.1/lib/doc/guide/chapter02 *** ds1.1/lib/doc/guide/chapter02 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter02 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,113 ---- + chapter 2 "The Vision Thing" + + Are you sure you want to run a mud? I mean, are + you *really* sure? + + Most newbie admins have no idea what a difficult + task lays before them. I started my own mud in 1995. + It's still around today, in fact. Back then, I'd + been coding on a mud that had its hosting pulled. I + finagled access to my university's systems and + told the old mud's admin "Hey, let's host it here!" + He didn't want to, so it was just me and my + new Nightmare IV mud. I figured "what the heck, maybe + I can run my own," and the rest is history. + + I hadn't a clue how to manage people, and things + just wouldn't come together. I had literally dozens of + creators come and go, and I could never figure + out why they'd build a few things and leave. The + problem was me, obviously. There was nothing about + the mud people disliked: Nightmare was a very popular + lib at the time. + The problem was that people wanted leadership + from me, and I didn't even know it, much less know + how to provide it. + + Creators ("builders") are your most precious resource. + Without them you don't have a mud, you have a lib. Sure, + you can try building everything yourself...and with + Dead Souls, that's not so farfetched an idea. But + after a few months of toil, you'll see that you have + weaknesses, you are not the perfect builder, and you + will wish for the help and support of others. + If you don't carefully cultivate your relationships + with these people, you will fail. Your mud will be a + failed mud, and your self-expression squelched. + + This is why I ask you if you're *really* sure you + want to run a mud. Running a mud isn't about lording + it over puny mortal players. It isn't about being + the sharpest lib coder logged in. It isn't about + bossing your staff, or making long lists of rules + and job titles and meeting schedules. + + Your job as an administrator is to manage + people, and guide them toward a single vision, over + which you yourself may not have full control. People + will listen to the admin at first because, well, she's + the admin. But if you can't demonstrate the qualities + of leadership they expect, they will stop respecting + you, and they will leave. Or worse, they will hang + around and be difficult. + + What's this about a "vision"? People will work for + a variety of reasons, mostly money, fun, recognition, + etc. Rewards. When your new coders show up, they + will need motivation to work. Since you probably + won't be offering much in the way of money or + recognition, you'll need to find a way to motivate + your coders by making it fun to work with you. + + Obviously I don't mean you need to be jolly and + wear funny hats. In fact, you can be quite boring a + person and still be good to work with. When I mean it + has to be fun for your creators, I mean that they + have to be inspired to do stuff...they have to *want* + to build because they are expressing themselves in + a way they enjoy. + + This means you'd be unwise to start parceling out + "missions" and "assignments". Find out what your new + creator *wants* to do, then do your best to + accommodate them. It's that simple. If they're working + on what they *want* to do, you don't need to actively + motivate them...you just need to make sure they + have what they need, and that they understand what + is expected of them. + + These expectations are the other part of the + individual management of creators. Just as is it + fatal to give creators "homework", it is just as + counterproductive to say "do whatever you want, man, + you're free to do anything." Part of the fun of + work is knowing what the standards are, and how your + work will be judged. If your creator feels like you + don't actually care what she builds, she won't + care much about doing a job that's up to any standards + but her own. After a while of this, she's going to + figure out she might as well just run her *own* mud. + + You therefore have to have a strong sense of what + your mud will look like, and what each creator's role + in that mud will be. If you don't know, or it seems like + you don't know, you'll lose them. + + You don't run the mud because you have the admin + password. You run it because people think you run it. + If they stop thinking it, you stop running it. + + So I ask again. Do you know what you want out of + this mud? Have you planned out what you want people + to be doing? When a talented coder shows up, will + you be prepared to negotiate their proper role, + and persuade them that the mud will succeed? + + Do you *really* want to be a mud admin? Or are + you just looking to be someone's boss? + + First, find your vision. Everything else will be + hard work, but if you know what your mud will be, + and what you need from other people, then you + just might have a chance to succeed. + diff -c -r --new-file ds1.1/lib/doc/guide/chapter03 ds2.1/lib/doc/guide/chapter03 *** ds1.1/lib/doc/guide/chapter03 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter03 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,79 ---- + chapter 3 "Getting Started" + + If you've read this far, there's a good chance + you already like the lib and are eager to get + going on this whole mud thing. Whether this is + true or not, this is where you find out for sure. + + Let's assume you're set with the vision thing. + You're going to make a mud with a Dora the Explorer + theme. You can practically hear the music even + now! Let's get this mud written and open! Vamonos! + + The first thing that happens here is you need + to get real familiar with this mud. If you haven't + done so already, when you finish this chapter, + you must do the following: + + 1) Read the Player's Handbook, cover to cover. + + 2) Create a test character. Do *not* use your + admin character's powers to give her any + equipment or money. Using the information from the + Player's Handbook, play this character until she + solves the Orcslayer Quest. Do not use any creator + characters to help her in any way. + + It is very important that you do this. It + is the best way you will know for sure whether you + have made the right lib choice. + + This doesn't mean that I'm asking you if you're + happy with the questing system, or how the items + in your inventory get listed, or whatever. Such + systems and cosmetics can be changed, sometimes with + trivial work. + What you're testing is the feel of the mud, + the parser, and that certain "I don't know what" + that tells you whether this is really a mud lib + you can live with. + + Don't like quest advancement? That can be removed. + Want turns-based combat? That can be arranged (though + not trivially). But if you get a low level discomfort, + and can't shake the feeling that you can't get + anything done, then this is when you'll find out. + + The second advantage to completing the Orcslayer + Quest is that it helps you see how things are + organized. As you proceed along the quest, you should + be using your admin character to examine the + files that compose the rooms, items, and npc's you see. + You will know where there are working samples of + doors, locks, hostile npc's, friendly npc's, spells, + and so on. This information will be valuable to you + in the next step you take. + + If you complete the Orcslayer Quest and decide + you still like the lib, your next step is to create a + small area. Read the Creator's Manual starting from + chapter 31. This provides you a detailed set of + instructions on how to get stuff built quickly and + painlessly. + Build a few rooms. If you can't think of something + to build, create a room just like the one you're + sitting in right now, including desk, door, and + scruffy mud geek sitting on a chair. + Or you might already know exactly what you want + to build. This is a good time to build a few + rooms of Dora's Grandma's House, or the tree house + of Tico the Squirrel. + + It's vitally important that you start using the + building tools, because just like with the Orcslayer + Quest, this is the point where you will discover whether + the build system here is a deal killer. + + Once you're done with your few starter rooms, you'll + be in a position to know whether you've really made + the right mudlib choice. diff -c -r --new-file ds1.1/lib/doc/guide/chapter04 ds2.1/lib/doc/guide/chapter04 *** ds1.1/lib/doc/guide/chapter04 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter04 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,70 ---- + chapter 4 "Gaining Experience" + + Now you must prepare for the + technical demands of your creators. + + Your creators will expect you to have + answers to their questions. For the most part, + they'll find these answers in the Creator's FAQ, + at http://dead-souls.net/ds-creator-faq.html . + + But you're going to get questions not on + that FAQ. You'll get stuff like: + + * How many quest points should the Issa Quest award? + + * What's the maximum player level on this mud? + + * Can I make a player class called "Swiper"? + + * What's a good weapon type for The Bouncy Ball? + + These are questions that depend strictly on you + and what your vision for the mud is. Dead Souls is + a starting point. The classes, levels, systems, + *everything*, is open to modification. + + It is normal and natural not to have all of + these answers at first. I suggest you concentrate on + making an "area", perhaps a quest, consisting of + perhaps 15 to 20 rooms and a few npc's, weapons, + pieces of armor and general items. + + Test your weapons and armor in the arena. To + get to the arena, first go to the Creators' Hall + by typing: wiz + + Then go east, then north. + + You can have the dummy wear armor like this: + + give mithril shirt to dummy + force dummy to wear shirt + + And you can test your weapons by beating on the + dummy: + + force fighter to drop sword + clone hammer + give hammer to fighter + force fighter to wield hammer + force fighter to kill dummy + + The dummy will very helpfully blurt out the amount + and type of damage it receives. + + You can get ideas for your npc's by visiting the + menagerie. It is east and south of the Creators' Hall. + + By creating your first quest, and putting test + characters through it, you will gain the experience + you need to be able to tell your players things like: + + "The Issa Quest is supposed to be easy, so make it 2qp." + + "Level 50 explorers are way too strong. I'm capping + player advancement at level 40." + + "No, there is already a thief class." + + "Make it a projectile weapon." diff -c -r --new-file ds1.1/lib/doc/guide/chapter05 ds2.1/lib/doc/guide/chapter05 *** ds1.1/lib/doc/guide/chapter05 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter05 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,111 ---- + chapter 5 "Guilds, Classes, and Clans" + + Section I: Classes + ------------------ + + I suspect you are already quite familiar with + the concept of classes. Some people even have very + strong feelings about classes, specifically, they + hate them. + + Dead Souls 1 came with a class system, and + I decided to keep it because it sort of worked, and + many people are familiar with classes and want to + have them on their mud. + + However, you don't have to use them. + + That's right. Using classes is not required. You + can very easily make your Dead Souls mud completely + devoid of classes, if that's what you want. + + The reason for this is that in Dead Souls, the only + thing a class does is confer on a player a class title, + like "Fighter", and load her up with skill settings appropriate + to that class. That's it. Classes do nothing more. + + If you want player X to have all the skills of a + fighter and all the skills of a mage, just make it so. + They don't need to have class to have skills. Add + "kite flying" while you're at it. It doesn't matter. + Dead Souls operates on a skill system. The class system + is incidental to it and can be dispensed with entirely. + + On the other hand, for those folks who appreciate + the role play and tactical elements involved in using + classes, Dead Souls provides you the ability to use + the existing stock classes, and permits you to create + your own. The files in /secure/cfg/classes describe them. + See http://dead-souls.net/ds-creator-faq.html#2.46 + for the exact syntax of these files. + + You'll notice that there is a field for "how important" + a skill is. What this modifier does is determine how + quickly your player's skill levels rise when her player + level rises. A fighter's magical ability does not increase + much when she is promoted a player level, but a mage's + magical ability certainly does. + + For those who find classes distasteful, this kind + of "skill hobbling" is just the reason they hate classes: + they feel they are too restrictive. If you are such + an admin, just dont use classes, and whenever you award + a skill to a player, set the "how important" number + (techninally known as the "skill class" but that's a very + confusing term) to the same for everyone. + + Incidentally, you don't *need* player levels either. + I will leave it as an exercise for the reader to imagine + a scheme where players do not have advancement levels. + + DS1 allowed players to join more than one class. + Unfortunately, the system was buggy enough and stripped + of classes so that it was both meaningless and a bit + of a problem. Multi-classing is by default not permitted + on DS2, but it's easy enough to implement on your own. + Review the header data in the class files to see the + syntax. + + However, since multiclassing isn't something I + am interested in working on right now, I will not be + assisting anyone in getting that to work. + + + Section II: Guilds + ------------------ + + The concept of "guilds" carries some baggage for me. I + learned about mudding by playing on Darker Realms, an LP + mud where a "guild" was effectively a class. There was + the mage's guild, the barbarian guild, etc. There were + also guilds that blurred the distinction between class + and race, like shapeshifters, cyborg, and dragon. + + When I ran into the Dead Souls 1 conception of guilds, + then, I was pretty confused. In DS1, a guild was + kind of a player-run club. There was a guild object + that made some sort of determination about who + was in or out, who was the boss, etc. My presumption is + that in later iterations of Nightmare V, these guilds + were fleshed out and worked properly. I presume this + because in DS1 they didn't, and they seemed to make some + assumptions about the lib that were not correct. + + I decided to change this for DS2, and the way it now + works is that guilds are neither classes nor player-run + clubs. The plan is to have guilds be not-necessarily-class- + based affiliations a player can have with balanced + advantages and disadvantages. As of DS2.0 there is no + working sample of this, but that's the plan for post + 2.1 development. + + + Section III: Clans + ------------------ + + Clans serve the purpose that DS1 guilds did. They are + player-run affiliations, managed by clan objects that + confer identity and status. As of DS2.0 there is no working + sample of this, but that's the plan for post 2.1 development. + + diff -c -r --new-file ds1.1/lib/doc/guide/chapter06 ds2.1/lib/doc/guide/chapter06 *** ds1.1/lib/doc/guide/chapter06 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter06 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,50 ---- + chapter 6 "Privacy" + + One of the most powerful and most easily abused tools + in your administrative arsenal is the snoop command. When + you "snoop <person>", you get to see everything they + say and do. + Players usually find this intrusive and objectionable, + and it is ethically shaky to do this without their + knowledge and consent. The only circumstances under which + snooping is unambiguously ethical are: + + * Snooping one of your own test characters. + + * Snooping a player (with their consent) for the purposes of + troubleshooting a bug. + + * Snooping a user (without their consent) to investigate + a legitimate suspicion of malfeasance. + + Secretly snooping people for your personal amusement is + just flat wrong. + + By default, only admins can snoop. Admins are players who + are members of one or both of the groups SECURE and ASSIST. + + An assistant admin *cannot* snoop a full admin. However, + assistant admins have read access to the snoop log directory, + so if global monitoring is enabled, they can read the + contents of a full admin's monitor log. + + The new SNOOP_D system allows for the simultaneous + snooping of multiple people, and allows multiple people to + snoop the same person. It also permits you to enable + monitoring of users without having to snoop, by using the + monitor command to log i/o to /secure/log/adm. + + The GLOBAL_MONITOR parameter in config.h will take one of three + arguments. 0 = monitor nobody. 1 = monitor everyone. 2 = monitor + everyone except admins. After changing it, reboot the mud + to make sure the change takes effect. + + This functionality isn't here for your entertainment. In + fact, I had to think long and hard before sharing my snoop + code with you and putting it in the general lib distribution. + + In the end, though, I believe that the benefits outweigh + the risk of abuse. As an admin, you have the right to know + what's going on in your mud, and as a lib coder, it isn't + my business to interfere with that. + diff -c -r --new-file ds1.1/lib/doc/guide/chapter07 ds2.1/lib/doc/guide/chapter07 *** ds1.1/lib/doc/guide/chapter07 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter07 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,167 ---- + chapter 7 "Advanced Topics" + + Section I: Shadows + ------------------ + + Shadows are a problematic topic. My first impulse is to warn + you sternly not to mess with them, they shouldn't be used, etc. In + his legendary LPC text, Descartes goes so far as to say he hasn't + seen a shadow do something that couldn't be done better another way. + + So, be aware that the topic of shadows tends to generate + strong opinions. + + Shadows *are* hazardous pretty much by definition. A shadow + is an object that effectively "wraps" another object, like an + invisible shadow around it. When a call is made to the shadowed + object, the shadow intercepts that call. + + What the shadow does with the call is up to you. It can + do nothing at all, and simply pass the call along to the + shadowed object. It could block that call. It could manipulate + that call and send the modified version to the shadowed + object. + + You can see an example of a shadow in /secure/npc/drone.c . + This is the code that enables you to take control of an npc + with the remote control. The remote control loads /shadows/drone.c + which inherits /secure/npc/drone.c , and attaches that shadow to + the npc that is to be controlled. This is a way of "adding + functions on the fly" to an already-loaded npc. + The drone shadow is in the lib as an example + of how shadows work, and an example of how to get an object to + posess functions it did not have when loaded. It is not + intended to represent shadow advocacy. + + The danger, and the reason some people go ballistic + when they hear the phrase "I think I'll use a shadow for that" + is that a lib that allows unrestricted shadow use + effectively has no security at all. You can have creators + enshadow an arch for example, or enshadow other privileged + objects. + + Dead Souls shadows are pretty tightly restricted. The + master object does not permit a shadow to be created unless its + code is in /shadows . This means creators can't hide their + rootkit shadows in their homedirs and expect them to work. + + Further, because /shadows is outside the /secure dir, + it serves as an obstacle to defeating the stack security + model. + + In any case, I strongly recommend you avoid using them + except in the extremely unusual case of a task that has + no other solution. If your mud starts collecting a bunch + of shadows out of laziness, sadness will likely be the result. + + + Section II: The "class" Data Type + --------------------------------- + + In 1995 Beek added a data type to MudOS: class. + I have to admit that I'm at a bit of a loss to explain classes, + because I am not a C guy, I'm an LPC guy. For people who + grok C, the class data type is a natural and elegant solution + for organizing related sets of variables. + + I have nothing but respect for Beek and the leet programmers + who built MudOS, so please don't go running around saying I'm + dissing them. + + But in my experience, the use of classes generally serves + the purpose of obscuring code and making it more difficult + to debug. + + I've seen newbie LPC coders take to classes like fish to water. + I can't explain it other than to speculate that for some people + the class data type (I've even had people argue at me that it's + really a "data structure", like I have the slightest clue what + the difference is) Just Makes Sense. If you are one of those people, + then bully for you. I'm serious. I don't understand you, but + your thing probably works for you, so, right on. + + However, I do not recommend that the average newbie coder + spend too much time on classes. You'll have plenty of opportunity + when you start dissecting the lib, but my friendly advice to + the noob is to use mappings instead. I've yet to see a class + do something that a mapping couldn't do with greater clarity. + + + Section III: add_action + ----------------------- + + Yet another topic with potential for violence. The passions + can run high on this one, and in fact, the Lima team felt + strongly enough about it that they don't enable it by default. + No add_actions by default. That's hard core. + + add_action is an efun that LP muds originally depended + on for most kinds of user input. If you wanted to be able to + throw a ball, that ball needed an add_action for it. You'd + have that ball provide a user with the throw command whenever + the user came in proximity to the ball. You can see the syntax + for add_action by examining the /lib/shop.c file. + + It's simple. It works. I mean, really, It Just Works, and + it's the fastest way to add functionality to any object. People + used add_action from pretty much the genesis of LP, as far as + I can tell, and it became just a way of life. That was just + how it was done. Yes, that wording was intentional ;) + + However, there were serious problems with this parsing + scheme. Basically it let any creator, regardless of skill + level, define commands for the mud. Joe's throw add_action for + his ball could be poorly coded and worded, and was liable to + behave differently from Jon's version. + + And suppose you held two or three items that had a throw + add_action each? Which one took precedence? What if that + one was bugged? + + Using add_actions for general lib command functionality + is really problematic for this reason. It fosters a lack + of uniformity across the lib that can leave users basically + playing a "guess the syntax" game for any item like this, + and allows for conflicts by incorrectly coded items. The + natural language parser was the MudOS solution to this problem, + implementing the verb system with which you are now so + familiar. + + The controversy boils down to preference. For some people, + add_action is just How It Is Done, and you still have + people starting muds with libs like Skylib and TMI-2 (!!) + that lack an advanced lib-wide parser. For these people, + verbs are an overcomplicated mess that they just don't + have a need to understand. + + Then you have the people who find add_action anathema, and + simply an unacceptable vestige of a more primitive form of + mudding. These people view add_actioners as atavistic knuckle- + draggers, either too dumb or too pig-headed to understand the + beauty and majesty of natural language parsing. + + My view, predictably, is somewhere in the middle. Verbs + *can* be exhausting to accommodate when you're just Trying To + Do One Thing. But add_actions truly are of limited use in + a modern lib, and allowing their proliferation out of + laziness is probably a bad idea. + + That isn't to say there isn't a place for add_actions. Dead + Souls supports them, and you'll see them every now and then. + In fact, technically, every command you issue, verb + or not, is evaluated by an add_action in the mud shell object + (LIB_NMSH). It is nevertheless better to learn to use verbs, because + they eliminate many problems you don't need to reinvent the + wheel for. + + I had one person tell me, as they chose a MudOS lib that + didn't use verbs, that they planned to write their own natural + language parser in the lib. I bade him good luck. I wonder + how he's coming along these days. + + + Section IV: Thoughts on MudOS + ----------------------------- + + Like, wow. MudOS. You know? + diff -c -r --new-file ds1.1/lib/doc/guide/chapter08 ds2.1/lib/doc/guide/chapter08 *** ds1.1/lib/doc/guide/chapter08 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter08 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,346 ---- + chapter 8 "Understanding the Lib" + + One of the most common questions I get goes something + like this: "I'd like to change combat so that it is + turns-based, with actions. How would I do this?" Another + example might be "I'm setting up a farming system, with + livestock and stuff. What should I look at?" + + To me, the questions are the same. Translated into + my language, this is the meaning: "I have great ideas that + require advanced knowledge of the lib to implement. How do I do it?" + + I'm usually at a loss when I get one of these, because + I want to set people straight, but I don't want to hurt + their feelings, either. In the FAQ's, my response is + something along the lines of: + + "If there's anything in the Creator's Manual you don't + understand, you aren't ready to try this." + + I hate to say that, because I think it's probably discouraging + to hear. After all, whatever the project, it is very likely + doable. You can make an LP mud do pretty much anything + you want...that's the beauty of the flexibility of LPC. + However, as they say, with great power comes great responsibility, + and in this case, it is your responsibility to understand the + lib, if you want to make major changes to it. Let's take the + example of farming. + + Section I: Verbs + ---------------- + + It is critical to understand how verbs work in order to + do anything in Dead Souls of an advanced nature. Verbs are + basically commands that do something to your environment, + something in your environment, your "body", or something + in your inventory. + + For example, "who" is not a verb. It's a standard command, + which doesn't act on any cloned items. All it does is communicate + with the lib to query the list of users logged on, and displays + it to you in a particular manner. + + Then there's something like "zap". That *is* a verb, and + it takes cloned items as arguments. When you "zap orc" this + has a special meaning to the parsing system. The parser is the + part of the game driver that tries to interpret your input + and attempts to do something useful with it. When the parser + catches a verb at the beginning of your input, it gets to + work on figuring out how the rest of the words in the input + relate to that verb. + + This is done through "rules". You can take a look + at /verbs/creators/zap.c for the specific rules in this case. + If the word or words (for example "first orc", "orcs", "an orc") + match one or more objects in the room, the parser then + sends the arguments to the verb object. The verb object is + the loaded code from /verbs/creators/zap.c in this case. + + Depending on how the verb is coded, your command line will + succeed or fail. + + For your new farming system, you're going to need some new + verbs, so the first thing you need to do is understand verbs. + You're going to have to build new verbs like "plow", and "plant", + and "harvest". Therefore, you'll need to go over the verb + tutorial, which is at http://dead-souls.net/verbs.html + + + Section II: Lib Event Objects + ----------------------------- + + In the verb tutorial, you read that when a verb acts on + an object, the parser requires that the object have a function + that handles that verb. If a chair object lacks a function + like direct_sit() or something similar, the parser will assume + your sit verb doesn't apply to chairs, and the command line + will fail with something like "You can't sit on the chair". + + It would be incredibly tedious to have to code a sit verb + handler in every piece of furniture you create. Similarly, + your farmer's field plow *could* have a plow verb handler + coded in it, but it is much better to create a lib object that + your plow will inherit. That way, other objects can inherit + that functionality without having to reinvent the wheel, and + plowing in general will be a uniform experience across the mud. + + For example, one of the first systems I made when + I started my lib obsession was the inheritable flashlight + system. The original Dead Souls lib had regular old torches + you'd light with a match, but it seemed to me that not every + Dead Souls mud would be Sword & Sandals style, and a modern + illumination system should be available. So I set about + making a "turn" verb, so that once I had flashlights, + you could "turn on the flashlight". + + I then created the lib object /lib/events/turn.c (when + referring to lib objects, I often use the macro name. In + this case, if I'd said LIB_TURN, it would be the same thing + as saying /lib/events/turn.c). The lib object doesn't really + *do* much of anything. That object isn't really where you + need to be checking for validity of commands. What that + object does, almost *all* it does, is to have functions that + correspond to the verb "turn". That's it. It's kind of like + a socket for a plug. The verb is the plug and you're trying + to use it on something. If that something has a socket + that fits your plug, then it'll work. + + Lib event objects come in different flavors, and some + really do perform a bunch of thinking. But for the most part, + for simple verbs, all you need is a lib event object that + says "yes, I understand that verb". + + LIB_TURN is inherited by LIB_FLASHLIGHT. That means + that when you clone an object that inherits LIB_FLASHLIGHT, + it contains all the functions of /lib/flashlight.c plus + all the functions that LIB_FLASHLIGHT inherits from LIB_TURN. + + Because your flashlight inherits LIB_FLASHLIGHT, + which inherits LIB_TURN, when you issue the command line + "turn on flashlight", the parser checks with the + flashlight to see if it knows what you're talking about, + and gets a "yes, I know that verb" response. At that point + the parser says "fine, here's the rest of what this + player thinks he can do with you and the turn verb" and now + it's up to LIB_FLASHLIGHT to figure out whether it has + enough batteries, of the right kind, with sufficient + charge, and so on. + + For your new farming system, you'll need to implement + a similar scheme. Your "plow" and "hoe" verbs will need + lib event objects that can be inherited by the cloned + objects you want to plow and hoe with. + + In this case, LIB_FLASHLIGHT and the turn verb + aren't the best models for your new plowing system. This + is because your plow is something you plow *with*, + as opposed to something that *is plowed*. + + To see how a plowing system might be implemented, + take a look at the "dig" verb, LIB_DIGGING, and + LIB_DIG_WITH. This is what a shovel would use, so + that you can "dig in sand with the shovel". After + studying the dig system, and lots of trial and error, + you will hopefully eventually come up with a + plow system that will let you "plow field with plow", + for example. + + + Section III: Daemons + -------------------- + + So, now you've created a plow verb, and a plow lib + event object, it works, and now you're happily plowing + along. Let's say that the rooms field1.c and field2.c + are plowable rooms. Presumably, you don't want people + to be able to plow here all the time. The fields need + time to do their thing, and constant plowing would + slow down the growth of your tender young corn stalks. + + Normally, you might deal with this by having + a local variable in the room, so that "harvest time is + 50 hours, unless someone plows again, which + makes it take longer", this sort of thing. Let's call + that variable PlowedTimes. + + But, oh noes! The mud rebooted! Now all the rooms + have reset, and the planting and plowing variables + have reset! + You might avoid this problem by just not rebooting, + but even if you manage never ever to reboot your mud, + the mud periodically does resets of unused objects, + retiring them from memory and resetting their values + to zero. + You might avoid *that* problem by setting your + fields to be "NoClean", to avoid resets, but this is + very inelegant. Rather than ensuring the integrity + of your game data, you're just crossing your fingers + and hoping it doesn't go away. + + The solution is to use a daemon. A daemon is an + object loaded into memory that acts like an arbiter + of information. For example, STARGATE_D keeps track + of where stargates are, and which gates are in + what state, and which gates are connected to each + other. It is important to have one location where + this data can be accessed, because a new gate must + be able to know what other valid gates there are, and + it must be able to know what gates are idle and + therefore accessible. STARGATE_D is a central + repository of this data, and serves as a mediator + for connection requests, keeping things working right. + + In this case, the daemon's job would be to + keep track of which fields have been plowed, how + many times, and how long it'll take to get to harvest + time. Dead Souls daemons typically use object + persistence files ( http://dead-souls.net/ds-admin-faq.html#80 ) + to avoid losing information during object reloads or + mud reboots. A FARMING_D is exactly what you need to + keep track of and manage this kind of data. + + + Section IV: Skills + ------------------ + + To what extent should people be able to plow? How + well should they do it? If you care enough about farming + to have come this far, you've probably got ideas about + what good plowing is and what criteria a player should + have for extracting the most from their land. + + This is where skills can play an important role. + What you have to understand about skills is that they + are simply variables in a player's body. Skills don't + have to be gained by joining a class, guild, or being + member of a race. Adding a skill to a player is as + simple as having an object do something like this: + + this_player()->SetSkill("scuba diving",1); + + And if just strapping on a scuba tank does it, then + now that player has that skill. + + Now, *normally* players are granted skills through + something more sensible than just picking up an object. + It makes more sense to have skills granted when a + player is taught something by an npc, or joins a guild, + or whatever, which is why traditionally that's how + it has worked. + + So let's say you have a Farmer's Guild, then. When + you show up and sign the registry, some npc pops out, + "teaches" you the farming skills you need (by simply + adding the skills "farming" and "plowing" and "sowing" + to the player) and now you have the skills. If you + want, you can even create a Farmer class, like Fighters, + but that's up to you and not in the scope of this chapter. + + This plowing skill is totally useless right + now. It does nothing at all, because you haven't yet + coded anything that makes use of it. This is the key + concept of the skills system that you must understand. + + Just giving a player a skill does not mean that + it has any use. For a skill to be useful, there + must be lib verbs and/or objects that evaluate the + skill and perform calculations based on it. + + It is therefore time to add these skill checks to the + objects that need them. For example, suppose our + farmer's plowing skill is at level 5. This doesn't + mean he's a level 5 player necessarily, just that + at plowing, his skill level is 5. + You might have a function in your /verbs/items/plow.c + verb that checks that skill, and determines how long + the field will take to grow based on it. Perhaps + for a level 5 plower, the field will be ready for + harvest in 45 hours. Perhaps for a level 10 plower, + it would be 35. You might have either the plow verb + or the plow lib event object do something like: + + int PlowFunction(string field){ + int skill_level = this_player()->GetSkillLevel("plowing"); + + if(skill_level) skill_level *= 2; + else skill_level = 1; + FARMING_D->eventModHarvestTime(field, skill_level); + return 1; + } + + It's a silly example, but you get the idea. The + "plowing" skill is valuable because the lib uses it + in some way to modify events the player performs. If + the lib doesn't know about it, the skill has no value. + + In the case of, for example, "blade attack", the + lib checks for this if you're wielding a sword and + you're in combat. Based on how good you are at blade + attack, combat.c will modify how much damage you + inflict when you hit your opponent. + + + Section V: Special Abilities + ---------------------------- + + Perhaps "plant" and "sow" are verbs that should + only be available to players with the skills "planting" + and "sowing". + Or, if farming isn't your thing and you want to + enhance combat, you might want Fighters who are members + of the Viking Guild to have a special ability called + "massacre" that can do extra special damage. + + This is best done by simply creating the sow, + plant, and/or massacre verbs, then coding the verbs to + work only for those people you designate. If the player + isn't a Fighter and a Viking, perhaps the massacre + verb would return something like "You have no idea + how to do that." and do no more. + + You are, of course, free to implement a Special + Abilities System along the lines of the existing Dead + Souls spell system. I encourage you to do so, if + you're so inclined, and to share that code with me, + if it works. But it isn't necessary. The existing + verb system is plenty sophisticated enough to + handle such special events. + + + Section IV: Summary + ------------------- + + At this point in my lib coder development, I have + a hard time distinguishing what is easy and what is + hard for new people. I have been surprised by people + who take a long time to grasp simple concepts. I have + been surprised by people who grasp complex concepts + so quickly that I can't answer their questions. + + Where you stand in that continuum I can't say. + What I can say is that if this chapter seems like it + went mostly over your head, you shouldn't worry too + much about it. It took me years of coding experience + and months of obsessed lib analysis to reach my + current level of understanding. You should not expect + yourself to grok everything in this guidebook the + first time around. + + As suggested in the previous chapters, it's best + to start small, slow, and steady. As you build simple + things, more complex things will make more sense, and + you'll eventually reach the level of technical + expertise you need. + + This chapter was not written to make you feel + overwhelmed by what you don't know. It was written so + that you understand what you're asking when you + say "How do I revamp bodies and limbs so they have + knees and elbows you can poke people with?" + + Once you understand the lib, it really really isn't + that hard to do. But if you are a beginner, don't + set yourself up for failure by taking a leap at a + project you don't have the experience to tackle. + diff -c -r --new-file ds1.1/lib/doc/guide/chapter09 ds2.1/lib/doc/guide/chapter09 *** ds1.1/lib/doc/guide/chapter09 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/guide/chapter09 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,67 ---- + chapter 9 "The Future" + + In the late 1990's, Descartes @ Nightmare released + a public domain version of the Nightmare lib called + Dead Souls, and pulled the official Nightmare lib from + distribution. They were very similar, but Dead Souls + lacked documentation. + + His final realease of Dead Souls was 1.1. + + As you must know by now, from reading the FAQ's (you + *did* read the FAQ's, right?) at some point I lost my mind + and decided to dust off that old lib, get it working, and + get people using it so that I could have other people to + discuss LPC code with. + + I can honestly say I didn't know what I was getting + myself into. I mean, when I started, it sure *seemed* like + things "mostly worked". The hard part was just getting it + installed, right? + + It's now been slightly over a year since I started + realizing that fixing A broke B, and fixing B broke A + and C, etc, ad nauseam. My guiding principle was "get it + working" with a corollary of "make it work well". My + main aim was bugfixes, but where a feature gap made it + obviously difficult for a beginner, I attempted to address + it with a new system. Hence, admintool, QCS, SNOOP_D, etc. + + In other cases, a new system was trivially easy + to add and its absence was an unreasonable burden, such + as SetAction for rooms. + + Sometimes a new system comes from my desire to have + a tool that makes my own life easier while fixing the + lib, such as the medical tricorder, remote control, and + the laboratory facility east of the Creators' Hall. + + For the most part, though, my main focus has been + fixing stuff, not adding stuff. The intention has been + to release Dead Souls 2.1 as a version that is as free + of pain as possible, as clear of bugs as reasonable, and + as fun and useful as 1.1 should have been. Today it is + May 18 2006, and I think that I am very close + to that landmark. Today I am at the point where the list + of bugs consists of minor annoyances, of the kind that + players would hardly ever take note. + + The future for Dead Souls I see as lots of fun for me. + I yearn to be free of doing nothing but fix fix fix. As + great as Dead Souls is, it needs major new systems to make + it fully competitive with the libs currently out there. + Adding these new systems is the kind of fun challenge + I'd really meant to be doing all along, but suckered + myself out of. + + Post 2.1 I intend to concentrate on things like + mounts, vehicles, naval/vehicle combat, 3d travel, extending + virtual rooms, player-independent world persistence, + and lots of other fun stuff. I'm not in the habit of + making promises about the lib. As the Dead Souls community + knows, I prefer to just *make* a new system than talk + about it. I wanted to share these plans with you, though, + so that you know that Dead Souls development continues + apace, and great things are on the horizon. + + diff -c -r --new-file ds1.1/lib/doc/hbook/chapter01 ds2.1/lib/doc/hbook/chapter01 *** ds1.1/lib/doc/hbook/chapter01 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/hbook/chapter01 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,50 ---- + chapter 1 "Introduction" + + If you are unfamiliar with LPC based muds in general or Dead Souls + mudlib in particular, you will find this handbook valuable in + orienting you around what you can do and how you can do it. + + Keep in mind that this handbook describes the features of a mud + running an unmodifed version of the lib. The mud you are on may + differ somewhat, though probably not extremely so. + + To advance a page in a chapter, just hit "return". + + Let's start with just navigating this book. Once you are done + reading this chapter, you can read the next chapter by typing: + + %^GREEN%^read chapter 2 in handbook%^RESET%^ + + Make sure you wait until you are done reading this chapter, + though. The reason you should wait is that you are now in "reading + mode", which means that anything you type and send to the mud + is actually a command to the editing system that is displaying this + text. + + To leave reading mode (or more accurately, pager, or ed mode) + you can hit "return" a bunch of times to complete the chapter, thus + automatically exiting the pager. Another way is to enter the + letter "q" (without the quotes) and then "return". That will also + make you stop reading. + + When you are not in reading mode, you can find out the chapter + titles by typing: + + %^GREEN%^read index in handbook%^RESET%^ + + You really should read the whole thing, but in case you don't, the + chapter titles will help as a reference to find the information you + need. + + Something to watch out for is that if you or your environment + contain another handbook, the mud may not know which one you are + trying to read. If you get a message like "Which of the two handbooks + would you like to read?", you can try one or more of the following: + + %^GREEN%^read index in first handbook%^RESET%^ + + %^GREEN%^read index in my handbook%^RESET%^ + + %^GREEN%^read index in my first player handbook%^RESET%^ + + diff -c -r --new-file ds1.1/lib/doc/hbook/chapter02 ds2.1/lib/doc/hbook/chapter02 *** ds1.1/lib/doc/hbook/chapter02 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/hbook/chapter02 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,273 ---- + chapter 2 "Command Syntax: Doing Stuff" + + + Section 1: Manipulating Objects + ---------- + + You've already noticed that Dead Souls, like most modern LP muds, + uses natural-like command syntax, like: + + %^GREEN%^read first handbook%^RESET%^ + + rather than: + + %^GREEN%^read handbook 1%^RESET%^ + + This is because Dead Souls uses a natural language parser. It isn't + perfect, of course. If you try to "put all apples from box in my bag after + opening them" you won't see much success, but this will work: + + %^GREEN%^open box%^RESET%^ + + %^GREEN%^open bag%^RESET%^ + + %^GREEN%^get apples from box%^RESET%^ + + %^GREEN%^put apples in bag%^RESET%^ + + The parser will understand "the first box" or "my second bag", + assuming those objects exist in your inventory or in your environment. + + If you want to know what is in the box, the command is: + + %^GREEN%^look in box%^RESET%^ + + The command "look at box" or "examine box" will usually *not* show + you the contents of that box. This is because normally, boxes are + opaque, and in the real world, just looking at a box is rarely enough + to see what it contains as well. + An exception to this rule are transparent containers (a glass + trophy case, perhaps) whose interior is always visible from the + outside. + + Sometimes looking at an object reveals its contents because of + the nature of the object. A table, for example, can have things on it, + and typing: + + %^GREEN%^look at table %^RESET%^ + + ...will usually let you know what is on it. It is also possible to + see what other players are carrying by just looking at them, + unless what they have is inside a container. + You'll want to remember that while you can "put apple in bag", + if you want to put that apple on a surface like a table, you'll + need to: + + %^GREEN%^put apple on table%^RESET%^ + + You can give things to people, and they will automatically + accept them. However, you may not "take" or "get" things from living + beings. It's theirs, and it's up to them if they want to share. + You can try to "steal sword from fighter" if you dare, but unless + you have trained a lot, this is unlikely to succeed. We'll talk + more about training and skills in a later chapter. + Naturally you may also drop things you no longer need, though + it's nicer to your fellow mudders (and the mud's memory) to put + them in recycling bins so the bits can be reused. + Some other common object manipulation commands are: + + close, donate, attack, eat, drink, listen, smell, search, + shoot, touch, turn. + + There are many others you may find useful, but these will be + the ones you use most often to handle simple objects. + + * A note about articles: + + Dead Souls understands both definite and indefinite articles. + This means that you can refer to a specific apple, like so: + + %^GREEN%^get the apple%^RESET%^ + + But you can also be unspecific. If there are a dozen + apples in a crate and you don't care which one you pick up: + + %^GREEN%^get an apple from the crate%^RESET%^ + + + Section 2: Navigation + --------- + + Moving around here is probably much like any other mud. You + can expect to move mostly in cardinal directions (like north and + northwest), but you may sometimes need to go up, down, or out. + Strictly speaking, the way to do this is: + + %^GREEN%^go south%^RESET%^ + + %^GREEN%^go out%^RESET%^ + + ...and so on, but this can get tedious after a while. Instead + of having to type in "go" plus the entire direction, the mud allows + you to enter shortcuts like "sw" for "go southwest" or "u" for + "go up". + + When you enter a room, very often you will see letters in + brackets above the room description, like this: [n, u, out] + These are the "obvious exits" of that room, and help you + quickly find your way around without having to go through each + description. But remember! Just because a room has obvious exits + doesn't mean those are the only exits. Sometimes a room must + be searched to discover an exit, or there may be an exit available + that just doesn't happen to be very obvious. + If a room is dark, obvious exits may not be visible at all. + + Aside from those ordinary means of travel, there are situations + that require more specific locomotion than just "go". These are + examples of the use of some other commands to get around: + + %^GREEN%^jump onto road%^RESET%^ + + %^GREEN%^enter window%^RESET%^ + + %^GREEN%^climb ladder%^RESET%^ + + %^GREEN%^crawl east%^RESET%^ (if you are lying down and can't get up) + + %^GREEN%^fly up%^RESET%^ + + %^GREEN%^follow thief%^RESET%^ + + %^GREEN%^evade hunter%^RESET%^ + + + Section 3: Armor + ------- + + Now that you can manipulate objects and move around, you'll want + to be able to defend yourself, should the need arise. The special + object categories of "weapons" and "armor" should help. + + Armor is an item that can be worn. That means that a pair of + blue jeans is considered armor, and a suit of chainmail is considered + armor as well. Basically, if you can wear it, it's "armor", because + whether it's a lot or a little, it protects you. + Assuming you are humanoid, you have the following limbs: + + head, neck, torso, right arm, right hand, left arm, + left hand, right leg, right foot, left leg, left foot. + + Properly coded armor must be worn on the corect limbs. Usually + a command like: + + %^GREEN%^wear chainmail%^RESET%^ + + or + + %^GREEN%^wear all%^RESET%^ + + ...will cause you to automatically wear armor where it makes + most sense. However, it is possible to find armor that, + for example, can be worn either on your neck or your torso, like + an amulet. If this is so, you'll need to specify where you want it. + There are various types of armor, like cloak, pants, glove, + etc. Many of them overlap. You can wear a shirt on your torso as + well as a cloak and combat armor, but you may not wear two of + the same type. If you have a robe and a cape that are both cloaks, + you'll have to decide which one is going on. + You will find that shoes and gloves are often for one of your + hands but not the other. Sometimes you will find shoes, or gloves + that don't care which appendage they occupy, but usually these + are simply incorrectly coded. + + If you are of some exotic or non-humanoid race, you may have + additional limbs to consider, and humanoid armor may not work for you. + + + Section 4: Weapons + --------- + + You may be surprised to learn that almost any manipulable object + can be wielded as a weapon, or thrown as a missile. You can wield + a can of Spam and try to kill an orc with it...and you may even succeed, + if you are strong and tough enough. Don't count on it, though, + and instead go for items that are made specifically with personal + security in mind. + + There are four main types of weapons: + + knife: knives, daggers + blade: like swords, and spears + blunt: like clubs, staves, and shillelaghs + projectile: things designed to be thrown, like darts or grenades + + Unless it is a special device or magical item, weapons + must be wielded in order to be of use in combat. Some weapons, + like staves or pikes, may require the use of both hands. If this + is the case, wearing a shield may not be possible at the same time. + Like armor, weapons differ in quality and effectiveness. A + "well-crafted sword" is probably a better choice than a "small + rusty knife", but then again, you never know. Maybe rusty knives + are exactly what some monster is most vulnerable to. + + Note also that, like armor, weapons wear down with use. + Examples of commands that involve weapons or fighting: + + %^GREEN%^wield sword%^RESET%^ + + %^GREEN%^wield hammer in left hand%^RESET%^ + + %^GREEN%^wield staff in left hand and right hand%^RESET%^ + + %^GREEN%^unwield dagger%^RESET%^ + + %^GREEN%^shoot gun at otik%^RESET%^ + + %^GREEN%^throw dart at beggar%^RESET%^ + + %^GREEN%^kill all%^RESET%^ (this makes an enemy of everyone in the room) + + %^GREEN%^ignore first orc%^RESET%^ (lets you concentrate on the other orcs) + + %^GREEN%^ignore all%^RESET%^ (don't fight anyone in the room, even if they are attacking you) + + %^GREEN%^target boss orc%^RESET%^ (this makes you ignore attacks from anyone else) + + %^GREEN%^wimpy 30%^RESET%^ (this makes you run away if your health points drop below 30%) + + + Section 5: Miscellaneous Things to to with Things + --------- + + %^GREEN%^turn on flashlight%^RESET%^ + + %^GREEN%^turn off flashlight%^RESET%^ + + %^GREEN%^strike match%^RESET%^ + + %^GREEN%^light torch with match%^RESET%^ + + %^GREEN%^extinguish match%^RESET%^ + + %^GREEN%^dig hole with shovel%^RESET%^ + + %^GREEN%^move bed%^RESET%^ + + %^GREEN%^search %^RESET%^ (by default searches the room) + + %^GREEN%^search rocks%^RESET%^ + + %^GREEN%^unlock east door with silver key%^RESET%^ + + %^GREEN%^bait pole with worm%^RESET%^ + + %^GREEN%^fish with pole%^RESET%^ + + %^GREEN%^stop fishing%^RESET%^ + + %^GREEN%^drop all%^RESET%^ + + %^GREEN%^donate 2 silver%^RESET%^ + + %^GREEN%^get all%^RESET%^ + + %^GREEN%^get all from corpse%^RESET%^ + + %^GREEN%^sell first right glove to otik%^RESET%^ + + %^GREEN%^sell all to otik%^RESET%^ + + %^GREEN%^buy sword from otik%^RESET%^ + + %^GREEN%^buy 8 from otik%^RESET%^ (get Otik to sell you item number 8) + diff -c -r --new-file ds1.1/lib/doc/hbook/chapter03 ds2.1/lib/doc/hbook/chapter03 *** ds1.1/lib/doc/hbook/chapter03 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/hbook/chapter03 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,255 ---- + chapter 3 "Your Health and Abilities" + + In the previous chapter you learned the basics of getting + around and taking care of yourself. It's important also to care + *for* yourself, and this chapter describes the various aspects of + your body's state and what abilities you may have. + + + The command that tells you almost everything you need to + know is "stat". This diplays a whole lot of stuff, perhaps some of + it completely unfamiliar. Let's start at the top, using my output + as an example. + + First line: + ---------- + %^CYAN%^Cratylus aka Cratylus the unaccomplished, level 10 male human Explorer%^RESET%^ + + Here you see my short name, my name with title, my level, my + gender, my race, and my class. Let's go over each. + + * short name: What a person would use to address you. "look at cratylus", + for example. + + * name with title: This displays my title. Creators can have whatever title + they want. Players can only have the titles they earn. As a player, a + title is usually earned when you are promoted a level or complete a + quest, though it is not always so on every mud. + + * level: This is a measure of your overall experience, expertise, and + all-around game status. Being promoted a level means your skills, + health, and vital statistics increase. This often means you can handle + tougher monsters, for example, or tackle more challenging quests, learn + new spells, and so on. + + * gender: This has no effect on your status. It is a cosmetic feature + of your body that is only useful to you in the social context of your + fellow mud players. + + * race: In Dead Souls, race has nothing to do with your local genetic + makeup on planet Earth. In the mud, "race" refers to what one typically + would call "species" in real-life. An example of a race other than human + might be "orc" or "feline". Not all races are available for players. Once + you have chosen a race to play, it is in theory possible to change it, but + there is a nonzero chance you'll hose up your player file and lose your + character forever. Besides, it's up to your local admins whether race + changing is permitted on your mud. Different races have different + abilities. Elves see better in darkness, for example. Orcs are stronger + than some other humanoids, but dumber, too (which does affect gameplay). + + * class: This can be considered an occupational specialty. In the real + world you have plumbers, doctors, soldiers, etc. In the mud world, + we can have explorers, fighters, mages, and the like. Each class brings + its own unique advantages and disadvantages to your gameplay. A fighter + can really kick more butt in melee combat than a mage, but a mage + gets to cast powerful spells. Explorers are a middle of the road class + that gives you a bit of everything without specializing in anything. + + + + Next line: + ---------- + + %^CYAN%^Alive / Awake%^RESET%^ + + It is indeed possible for your virtual body to cease life functions. + When this happens your spirit speeds off to the land of the dead, + where you drift until you decide to "regenerate" and regain your + physical form. Except for some special magical items, anything you + were carrying when you died is with that dead body, so it's a good + idea to rush your new body back to the scene of the fatality and get + your stuff back before someone else grabs it. Death is not only + inconvenient, it also incurs major penalties on your statistics, so it + should be avoided. + It is also possible to sleep. If you are drunk and asleep, your + injuries will heal more quickly. It's magic, don't worry about the + logic behind it. + If you are attacked while sleeping, you will wake up. You can + force yourself awake, too, but it's a bit tedious. + + + Next line: + --------- + + %^CYAN%^Health: 350/350 Magic: 560/560 Stamina: 400/400 Carry: 1184/1300%^RESET%^ + + In each case, the number on the left of the slash indicates the + current level, and the number on the right indicates what the maximum is. + + health: When I am 100% healthy, I have a total of 350 hp. If my hp ever + reach 0 or less (!), I die. Poison and illness can cause hp's to + gradually decrease, and although with time my hp's will normally + return to 350 as I heal, poison and illness can slow down that healing + or even cause me to die. Injury in combat is the most common source + of hp loss, though spells, falls, and other adverse events can cause + you injury or death. + + magic: I cast magic missile! Spell casting takes a toll on your magical + abilities, and mp measure how much magic you've got left in you at + any given point. Like hp, mp gradually grow back to your max if you + avoid spellcasting for a while. + + stamina: Fighting is tough work, and swinging around swords while + getting bashed with hammers really takes a lot out of a guy. Therefore + keep an eye on this stat while you're fighting, because if it gets too + low you will collapse and be unable to do anything for a while. + + carry: Objects have mass, and your body is of limited size and strength. + My carry capacity is 0 when I carry nothing, and 1300 when I can + carry no more. Creators are allowed to exceed their bodies' carry + capacity, but players cannot. + + + Next line: + --------- + + %^CYAN%^Food: 0 Drink: 0 Alcohol: 0 Caffeine: 0 Poison: 0 %^RESET%^ + + These are pretty self-explanatory. Alcohol is good for healing, + bad for fighting. Food and drink also help speed healing. Poison + has the opposite effect. Caffeine can speed up your combat slightly, + but tends to prevent full rest. + You will not die from lack of food or lack of drink, but you + will do better with a body not starved for nutrients. + Your maximum load for any of these is not fixed, and varies + depending on many factors, such as level, endurance, etc. + + + Next line: + --------- + + %^CYAN%^Training Points: 0 Quest Points: 0 Experience Points: 50 %^RESET%^ + + Training points can be cashed in with special NPC's called + trainers, who can help you improve some skills. A trainer that + specializes in fighting might be able to raise your "blade attack" + skill, for example. you earn training points when you are + promoted a level. + + Quest points are awarded when you complete a quest. In + the default version of Dead Souls, you cannot advance past a + certain player level unless you earn some qp's. Read the sign + in the adventurers guild for more details on this. + + Experience points can be awarded for various reasons: completing + a quest, solving a puzzle, winning a contest. Most often you + will receive xp after killing an NPC. The amount of xp awarded + will depend on the level of the NPC. Like qp, xp are needed to + qualify for level advancement. + + + + Limb section: + ------------ + + Remember how wearing armor requires the right body parts? + Well here they are, and this is their health. You can issue the + "body" command for a quicker self-check. + Let's look at what the numbers mean with an example: + + %^CYAN%^left leg (2) 160/160%^RESET%^ + + Obviously the first item identifies the limb in question. + + The (2) is a kind of "importance score", indicating how critical + a body part is. If this number is (1), like the head, it means that + losing that limb causes immediate death. + + The number on the right side of the slash indicates the hit point + damage you may receive on that limb before it is severed. The number + on the left is how many of those hits you have left. + It doesn't mean my leg has 160 of my hitpoints. If that were true, + my hit points would add up to a heck of a lot more than 350. + This means that if I've lost, say, 200hp fighting a troll, and + 159hp of those hits were on my left leg, getting hit there again means I + lose my left leg. + I would then collapse and have to crawl away to seek medical attention. + Wearing armor on your limbs is a great way to minimize the danger of + this happening. + + + Skills section: + -------------- + + Let's review skills by examining one of mine: + + %^CYAN%^blade attack (1) 00% - 20/24%^RESET%^ + + This measures how likely I am to hit an opponent when I + use a blade, and how good a hit it was. The number (1) means + that this is a skill critical to my class. If an explorer can't + swing a sword, he oughta think about another line + of work. + The 00% means I have thus far earned no blade attack + experience toward achieving the next level of this skill. + The 20 is my current proficiency level. + The 24 is the maximum level I can reach at my current + player level and with my current stats. + + What's all this mean? Well, if I practice a lot of blade + attacking, that 00% will gradually climb up to 99, and one more + point causes me to go from a level 20 slicer of things to a + level 21 slicer of things. This increases my likelihood of + hitting my target in the future. + + Meaning, in short, practice a skill, and you'll get + better at it. + + Of course, if my blade attack level reaches 24, I can advance + my blade attack skills no further until my player level rises. + + + Stats section: + ------------- + + Remember these from Dungeons & Dragons? No? Well these vital + statistics measure your general giftedness in that feature of your + body. Let's look at one of mine: + + %^CYAN%^coordination (2) 42/42%^RESET%^ + + Coordination is one of those important stats for fighting and + such. The more coordinated you are, the more likely you are to hit your + target. The (2) indicates that this stat is important to my class, + but not critical. This influences its effect on my skills. + 42/42 means that my coordination is not currently impaired. If + someone cast a "stumble" spell on me, for example, this might look more + like 30/42, and if I were drunk, it would look very shabby indeed. + + Last section: + ------------ + + "Cratylus has amassed a net worth of 11 gold." means that when you + add up the money in my bank accounts and the money I'm carrying, + converted to gold, I have 11 gold to my name. It looks bad, but gold + is actually quite valuable in the default Dead Souls economy. + + "Money on hand: 79 dollars, 34 silver" means that this is the amount of + money I'm carrying. Don't forget that the amount of money you are carrying + affects your overall carry capacity. Gold is an especially heavy + currency. + + + Final notes: + ----------- + + "stat" is a great command to get thorough information about + yourself. It is, however, quite a screenful. Briefer reports can be + viewed with the following commands: + + %^GREEN%^body%^RESET%^ + %^GREEN%^skills%^RESET%^ + %^GREEN%^stats%^RESET%^ + %^GREEN%^score%^RESET%^ + %^GREEN%^status%^RESET%^ + diff -c -r --new-file ds1.1/lib/doc/hbook/chapter04 ds2.1/lib/doc/hbook/chapter04 *** ds1.1/lib/doc/hbook/chapter04 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/hbook/chapter04 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,69 ---- + chapter 4 "Quests" + + Some muds don't have quests, and the fun people have is + through role-playing and social activities with other players. + + Other muds prefer to concentrate on killing lots and lots + of monsters, a lot, over and over. + + Quests give you a chance to problems-solve by performing some + series of actions that satisfies a pre-determined requirement. + + For example, Dead Souls' sample town contains a quest called + Orcslayer. Leo the archwizard lives in the basement of the old + abandoned church, and he has lost a powerful magic sword called + "Orcslayer". If you return it to him, he will reward you with + experience points, quest points, and a new title you can use. To + complete the quest, you need to defeat the warrior orcs, penetrate + deep into their lair, defeat the orc shaman, and take Orcslayer from + his corpse, then go to the church basement and give the sword to Leo. + + In this case, if you're a level 1 newbie, the orcs will massacre you + before you get anywhere near the shaman. So either team up with + friends to tackle the orcs together, or raise your level to the + point where you're tough enough to take them on. + + To raise your level, wander around in the newbie mansion, which + is south of the village church. + + There's lots of loot there you can sell at Otik's shop, and with the + cash you can then get some proper weaponry and armor. + + Silver is heavy, so don't try to carry all your money around + all the time. Request an account from Zoe the banker and keep your + money there until you really need it. + + There is a quest in the newbie mansion, and solving it by + finding the secret room will give you experience and quest points too. + (hint, there might be more than one secret room) + + Once you have enough experience and/or points, go to + Dirk in the adventurers hall and "%^GREEN%^ask dirk to advance%^RESET%^". + + Make sure you learn some spells from Herkimer, because if you + go up against a bunch of orcs in their lair, you'll want spells to + shield you from attacks, and spells to recover your strength after + combat. As a non-mage, your spell abilities will be limited at + lower levels, but as you gain levels you'll get better. Also, spells + will rarely work after you first learn them. Keep casting them, + even if you screw them up, so that your magic skills increase. + + Also, save your money. Drinking and sleeping help you heal, + but not fast enough. By the time those natural processes finish + and you're ready for combat again, the orcs may have gotten reinforcements. + So if you can afford it, buy healing slips and use them at Clepius' + healer's guild. His treatment is expensive, but you will heal much + more quickly. + + In the tragic event of the loss of a limb, Clepius can also magically + regenerate a new limb...but obviously at some great cost. + + There. I've just spoiled the Orcslayer quest for you. Normally, + all you'd know about a quest is a cryptic clue, like the one in the + scroll in the adventurers guild. Instead I've just spoiled the quest + for you by telling you all about it. They're more fun when you have to + figure them out on your own, like puzzles. + + Normally, spoiling quests like this is a bannable offense on + a mud, so if you solve a quest, keep it to yourself unless you know + the admins on your mud don't mind. diff -c -r --new-file ds1.1/lib/doc/hbook/chapter05 ds2.1/lib/doc/hbook/chapter05 *** ds1.1/lib/doc/hbook/chapter05 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/hbook/chapter05 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,106 ---- + chapter 5 "Communication" + + There are many ways to communicate with other players. If + you're in the same room as your intended listener, you can just + use the "say" command, like this: + + %^GREEN%^say hi, crat%^RESET%^ + + If the message is secret, you can "whisper": + + %^GREEN%^whisper to cratylus are you idle?%^RESET%^ + + If you want to say something that everyone in the mud can + hear, use the "shout" command (at the cost of a lot of stamina): + + %^GREEN%^shout hey crat, wheredya go?%^RESET%^ + + Or, if it's an important secret and the target is not in the + same room as you, you can use the magical "tell" command: + + %^GREEN%^tell cratylus are you mad at me or something?%^RESET%^ + + + There are also special communication lines on the mud that are + class or role-specific. For example, if you type: + + %^GREEN%^newbie does anyone know what's up with cratylus?%^RESET%^ + + All people who are tuned into the newbie line will get + your message. To see what lines are available to you, type: + + %^GREEN%^lines%^RESET%^ + + To see who is listening to the newbie channel: + + %^GREEN%^list newbie%^RESET%^ + + To see who is listening to some other channel on some other mud: + + %^GREEN%^list otherchannel@othermud%^RESET%^ + + + To enable or disable a line, just type the name of it with no message. + + To see a brief history of the past few messages on a line (in + this case, the newbie line), type: + + %^GREEN%^hist newbie%^RESET%^ + + + Spamming lines is rude and probably dangerous to your character, so + be sure you comply with your mud's rules on lines. + + + Your mud may be on the intermud network. To find out, type the + command: + + %^GREEN%^mudlist%^RESET%^ + + If a list of muds comes up, you know your mud is probably + on the intermud3 communication network. Dead Souls by default restricts + players from access to intermud channels, but you can "tell" to + players on other muds, if you want. If you think your friend Xyzzy + is online on a mud on intermud3, you can issue this command: + + %^GREEN%^locate xyzzy%^RESET%^ + + If he's logged into a mud on i3, you will get something like: + + Xyzzy was just located on Frontiers. (idle 00:03:17) [status: inactive] + + You can then tell to him: + + %^GREEN%^tell xyzzy@frontiers dude, what's the deal with crat lately?%^RESET%^ + + + Sometimes a player or NPC does not understand your character's + native tongue. For example, if you are en elf, your native tongue is + not English, it is Edhellen. If someone talks to you in English, you + might see something like this: + + Xyzzy says in English, "leka mifahmam, potong-hwa." + + Since your character doesn't speak English, what you see is gibberish. + If you find a language teacher, your proficiency in the language they + teach you will allow you to understand more of the words you hear. + + Suppose that your elf character is now 100% fluent in English. + If you greet a human player named Xyzzy by typing: + + %^GREEN%^say hello there, xyzzy%^RESET%^ + + Xyzzy will probably see something like: + + Noobie says in Edhellen, "pericolo temak, forshtor." + + Instead, if you want to speak to a human, you'll have to type: + + %^GREEN%^speak in english hello there, xyzzy%^RESET%^ + + + To find out what languages you speak, type: + + %^GREEN%^language%^RESET%^ + + diff -c -r --new-file ds1.1/lib/doc/hbook/chapter06 ds2.1/lib/doc/hbook/chapter06 *** ds1.1/lib/doc/hbook/chapter06 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/hbook/chapter06 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,13 ---- + chapter 6 "Note to New Creators" + + You should probably hang on to this book for reference. If + you lose it, pick up a copy at the adventurers hall. + + However, you need to start reading the Creators Manual. If + you don't have one on you, get the one in the chest in your workroom. + + If you're new to coding, start with chapter 31. It'll + get you started with the Quick Creation System, or QCS. + + Cratylus @ Frontiers + 04 Jan 2006 diff -c -r --new-file ds1.1/lib/doc/hbook/chapter07 ds2.1/lib/doc/hbook/chapter07 *** ds1.1/lib/doc/hbook/chapter07 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/hbook/chapter07 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,71 ---- + chapter 7 "Hints and tips" + + * The "wimpy" command helps you avoid death due to inattention or + network lag. If you "wimpy 20", you will automatically try to escape + combat if your health goes below 20% of your maximum. + + * "target" and "ignore" are extremely useful when fighting more than + one enemy. You should always target the toughest npc first, and + always ignore any npc who can't get up because their foot or leg + is severed. + But if they collapse due to exhaustion, it's a good idea to keep + beating on them, otherwise they may get back up and get healthy sooner + than you expect. + + * By default, different races speak different languages. If someone + says something to you and you see no words in the same language as + the rest of the mud, it means they are speaking a language you do + not understand. + For example, if you are an elf, and you ask Radagast to teach + magic attack, you might get something like this: + + Radagast exclaims in English, "embleer con boltehe oota goota nehi auch" + + Even though in the real world you may speak English fluently, in + the mud world, you do not speak English fluently. As an elf, your + native tongue is Edhellen, and you may find human speech incomprehensible. + + If you find a trainer to teach you English, your skills in that + language will need time to improve. As you get better at a language, + you will see fewer gibberish words. + + If you are a "newbie", this does not apply to you. A newbie in the + default Dead Souls distribution is a player at level 4 or below. This + definition may be changed by your admin. + Newbies need all the help they can get just to survive, so they + are magically granted understanding of all languages, until they outgrow + their naivete. + + If you are a student of languages in the Real World, you may + recognize many of the "gibberish" words used by Dead Souls to represent + a foreign tongue. Your understanding of these words is not useful in + the context of the game, however, because they are not intended to + convey meaning other than "non-comprehensible words". + + + * Your ability to see is affected by various things: + + - A room's ambient light level + - Time of day + - Local light sources (flashlights, torches, etc) + - Your race's light sensitivity + - Magical effects + - Exposure to an excessive-light event + + It's important to remember that a room may be too dark for + you to see everything in it. You might be able to see the description + of a room with no problem, but it may be necessary for you to + light a torch in order to see the treasure chest there. + + In the same way that darkness can impair vision, brightness + can do the same. For elves, an outdoor area in bright sunlight that + contains additional light sources can be just as hostile to + vision as a dark cave with no torch would be for a human. + Regardless of race, a sufficiently adverse event, such as + a bright flash or special spell, can render you temporarily blind. + + As with languages, newbies have some exemption to light-level + limitations. + + * Mages can wield knives but are pretty much helpless with any other + vind of edged weapon. diff -c -r --new-file ds1.1/lib/doc/help/classes/cleric ds2.1/lib/doc/help/classes/cleric *** ds1.1/lib/doc/help/classes/cleric Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/classes/cleric Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,27 ---- + Dead Souls LPMud Cleric Class + Originally written 951129 by Descartes of Borg + Last modified 951129 + + The cleric holds the natural world in highest esteem, shunning + violence and things unnatural. They specialize in the healing arts + and defense against magic and blunt weapons. They also have powers of + faith which draw from the gods of the natural world they worship. + + A person who chooses to play a cleric will never fight powerfully. + Instead, people playing clerics + play the class because they enjoy working with teams to accomplish a + task and also because they love helping others. Clerics are most + often seen as doctors or party healers in adventuring groups. + + One exception to the cleric non-violence oath is their power over the + unnatural world of the undead. Their faith bestows upon them the + ability to rid the world of the undead, or to bring the undead back to + the world of the living. + + Primary Skills: + faith + healing + blunt defense + magic defense + + diff -c -r --new-file ds1.1/lib/doc/help/classes/mage ds2.1/lib/doc/help/classes/mage *** ds1.1/lib/doc/help/classes/mage Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/classes/mage Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,22 ---- + Dead Souls LPMud Mage Class + Originally written 951202 by Descartes of Borg + Last modified 951202 + + Mages are powerful magic users who make their livings through their + magical talents. They are an integral piece to any adventuring group, + as many situations require the use of magic to change the way the die + have been cast. Given so much attention to the magic arts, however, + mages find themselves poorly suited to weapon-based combat. Thus, + when engaged in combat, mages tend to rely instead on their magic + talents to avoid damage and strike at their opponents. + + The mage class is perhaps better suited to the hack-n-slash style of + player, through role-players and socials can likely find attractive + characteristics in a well played mage. + + Primary Skills: + conjuring + magic attack + magic defense + projectile defense + diff -c -r --new-file ds1.1/lib/doc/help/classes/thief ds2.1/lib/doc/help/classes/thief *** ds1.1/lib/doc/help/classes/thief Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/classes/thief Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,20 ---- + Dead Souls LPMud Thief Class + Originally written 951202 by Descartes of Borg + Last modified 951202 + + Thieves are an extremely varied bunch of scum who spend their days + practicing the less accepted crafts of society. Though skills such as + lock picking are often desired in adventuring parties, skills such as + stealing make people avoid them. + + Thieves are designed for people who like to role-play and adventure in + groups. The role-player will find the unique character of being a + thief challenging, and people who enjoy group adventuring will find + their skills in high demand. + + Primary Skills: + bargaining + stealing + stealth + knife attack + diff -c -r --new-file ds1.1/lib/doc/help/creators/addemote_help ds2.1/lib/doc/help/creators/addemote_help *** ds1.1/lib/doc/help/creators/addemote_help Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/addemote_help Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,50 ---- + [ Addemote General Help ] + + Note: All examples are from the 'emoter' perspective. + Basic emote: $N smile $A. + - $N is the name of the emoter. $N *must* be used in both + (emote) and (environment) fields to preserve functionality. + This means do not enter 'You smile $A.'. + + - $A field means the user can specify any adverb from the soul's + pool of adverbs. (This also applies to any specific adverbs + (assigned to the emote). If the user does not specify an adverb, + and no default adverb is set, this field is ignored. + + Targeted Emote: $N smile $A at $T + - $T field displays the name of the target (player). If no + target is found, A 'no target' emote will be used in place + of targeted. + + Locations: $N pokes $A $T $X + - $X acts the same as $A, only it searches through a list + of locations assigned to the emote in question. If no + location is specified by user, and a default setting exists, + it will be used automatically. Otherwise, $X is simply ignored. + Note that all locations are prepended with an assigned + preposition (if used). (example: locations set to 'nose, head, + ear', preposition set to 'on the'. + + Extra Field: $N scratch $* + - If the $* field is used, all lefteover arguments will be + put here. + + [ List of valid fields ] + + $N - Name of the 'emoter' + $T - Name of target + $NP - emoter possessive (his) + $TP - target possessive + $NO - emoter objective (him) + $TO - target objective + $NR - emoter reflexive (himself) + $TR - target reflexive + $NA - possessive form (name's) + $TA - target possessive name + $A - display adverb (ignored if + none is specified by user) + $X - display defined location + (prepended with preposition if used) + $* - display any extra arguments passed by user + + diff -c -r --new-file ds1.1/lib/doc/help/creators/admin ds2.1/lib/doc/help/creators/admin *** ds1.1/lib/doc/help/creators/admin Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/admin Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,43 ---- + Dead Souls Administration + + Being a successful MUD admin is heavily dependent + on how well you can get stuff done. It also depends on + your ability to manage people, resolve conflict, articulate + direction, enforce guidelines, and inspire loyalty. + But those other things I can't help you with. What + I can help you with is having the tools you need to get + stuff done. + + Your most valuable tools will be the Dead Souls FAQs: + + http://dead-souls.net/ds-admin-faq.html + + http://dead-souls.net/ds-creator-faq.html + + Almost everything else will flow from your + familiarity and understanding of the information there. + + Navigate to the /secure/cmds/admins directory. This + is where your commands are. Know them. Understand them. + In particular, pay close attention to the command: + + admintool + + It is a valuable tool for new admins to get important + stuff done before they are 100% familiar with everything + they need. + + Finally, the intermud Dead Souls community is a + vital resource. They are (thus far) friendly and helpful, + and if the Player's Handbook, Creator's Manual, and + the (upcoming) Admin's Guide don't have the answer, use + the <ds> channel to ask for help. + + As to the qualities of leadership, determination, + humility, responsibility, fairness, and selflessness you'll + need to make a successful mud, you are on your own. + + Good luck. + + - Cratylus @ Dead Souls + 05 May 2006 diff -c -r --new-file ds1.1/lib/doc/help/creators/creation ds2.1/lib/doc/help/creators/creation *** ds1.1/lib/doc/help/creators/creation Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/creation Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + Dead Souls Quick Creation System + + One of the biggest obstacles to creating a large area is the tedious nature + of coding every last detail by hand, using the ed editor. + + This new creation system helps relieve the tedium by providing + a way to quickly create working stuff, which you can then conveniently modify + without having to continually muck about in ed. + + There are still things you need to do with ed, such as searches, complex + exits, and the like, but the bulk of your building will go much more + quickly using the new system. + + A thorough builder's manual on using the new system is in the works. + + In the meantime, take a look below at the commands in actual use, with a + few added comments: + + http://dead-souls.net/example.html + + diff -c -r --new-file ds1.1/lib/doc/help/creators/creator_general ds2.1/lib/doc/help/creators/creator_general *** ds1.1/lib/doc/help/creators/creator_general Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/creator_general Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,21 ---- + Common Creator commands: + + File commands: + ------------- + cp - copy a file + mv - move or rename a file + cd - change your working directory + ls - list the contents of your directory + ed - edit a file (WARNING: if you get stuck, type a + single period on a blank line, then Q, then enter) + rm - delete a file + more - page through the contents of a file + cat - display the entire contents of a file + update - load a file into memory + + Creation commands (used on objects, not files): + ------------- + create, modify, reload, delete, add, copy + + For more information on a command, type: help <commandname> + See also: help help diff -c -r --new-file ds1.1/lib/doc/help/creators/debug_hints ds2.1/lib/doc/help/creators/debug_hints *** ds1.1/lib/doc/help/creators/debug_hints Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/debug_hints Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,48 ---- + There is another LPC debugging technique that provides a good supplement + to the debug(x,y) macro provided by debug.h. + + Suppose that your object won't load and the logfile isn't specifying where + the error is. You can use the #if 0 preprocessor directive to selectively + temporarily remove suspect pieces of your code. Note that using #if 0 is much + cleaner than commenting the code out using /* and */. One reason its cleaner + is that it is possible to nest #if directives but not comments. Another + reason is that you can add the code back simply by changing #if 0 to #if 1. + + Suppose you had the following function that was giving you problems: + + void xyz() + { + statement_1(); /* statement 1 does blah blah */ + statement_2(); /* statement 2 does blah blah */ + } + + Suppose you suspected that statement_2() was causing the error. You could + temporarily remove that line by changed xyz to read: + + void xyz() + { + statement_1(); /* statement 1 does blah blah */ + #if 0 + statement_2(); /* statement 2 does blah blah */ + #endif + statement_3(); /* statement 3 does blah blah */ + } + + Suppose that you had used comments instead of #if 0 to remove statement_2(). + + Suppose you tried it like this: + + /* + statement_2(); /* statement 2 does blah blah */ + */ + + This method would cause a compile error because of the nested comments. + + Therefore, it would have to look something like this: + + /* statement_2(); */ /* statement 2 does blah blah */ + + But this method is bad because its a royal pain to insert and remove comments + within a line using the ed line editor (IMHO). + + --Truilkan@TMI diff -c -r --new-file ds1.1/lib/doc/help/creators/debug_macro ds2.1/lib/doc/help/creators/debug_macro *** ds1.1/lib/doc/help/creators/debug_macro Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/debug_macro Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,44 ---- + The debug.h include file provides a very simple yet suprisingly powerful + debugging mechanism. The benefits provided by debug.h include: + + 1) conditional compilation - meaning that debug(x,y) expands to an empty + statement (;) if DEBUG_MACRO is not #defined. This lets you leave in debug + statements in case something goes wrong at a later time (in which case + you simply #define DEBUG_MACRO once again). + + 2) Lets one define sets of debug statements that are turned on or off as + a group. In the normal course of debugging a program, one adds several write + (or tell) statements in an attempt to track down an current error. After + fixing these errors, the debug statements get deleted and its on to + tracking down the next error in the program (adding a new set of debug + statements). The problem is that sometimes the original error comes back + (under a different set of circumstances) and gee wouldn't it be nice if that original set of debug statements was still there. The debug.h + include file provides a convenient way to do this. Returning to the + concept of turning sets of statements on or off as a group. It is + also possible turn sets of sets on or off as a group. + + debug(x,y) is defined to be something like: + + if (x & _debug_level) write(y); + + Note the use of the bitwise/and operator. This operator is what gives + the debug macro its flexibility. The write statement gets executed only + when one of the bits set in the integer _debug_level is also set in the + variable x (the first argument to debug(x,y)). As an example of how this + might be used: in the early stages of debugging a program you might + set_debug_level(1) and use debug macros of the form debug(1,y). After + a period of debugging you might feel that the debug(1,y) statements have + served their purpose. At that point, you can change the set_debug_level + call to be set_debug_level(2). Now, the debug(1,y) statements will no + longer cause anything to be printed. However, debug(2,y) statements would + be printed. Suppose that an old error crops up because of a new set of + inputs that you didn't encounter before. If the debug(1,y) statements + would again be helpful in debugging this old error, you could + call set_debug_level(3) instead of set_debug_level(2). This would cause + BOTH debug(1,y) and debug(2,y) statements to issue writes. This is because + the binary representaton of three (3) contains a one (1) AND a two (2). + + See /obj/debug.c and /usr/include/debug.h for a concrete example of how + this works. + + --Truilkan@TMI diff -c -r --new-file ds1.1/lib/doc/help/creators/debugging ds2.1/lib/doc/help/creators/debugging *** ds1.1/lib/doc/help/creators/debugging Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/debugging Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,166 ---- + Debugging in Dead Souls + + So you've made some cool stuff but darn it, it doesn't work. There are various + tools available in the Dead Souls lib to hunt down the source of the problem: + + + %^GREEN%^elog%^RESET%^ + + If the file is somewhere in your home directory, just type: elog + + This will provide you a listing of the last few lines of your personal + error log. Warning lines tell you about code that works but should + be fixed in some way. Lines that don't contain the word "Warning" are + error lines: they indicate something about your code that prevents + it from working. For example: + + > %^GREEN%^update sample_room%^RESET%^ + + --- + *Error in loading object '/realms/cratylus/area/room/sample_room' + Object: /secure/cmds/creators/update at line 148 + + '<function>' at /secure/save/creators/c/cratylus (<function>) at /:0 + 'cmdAll' at /secure/save/creators/c/cratylus (/lib/command.c) at line 84 + 'cmd' at /secure/cmds/creators/update at line 109 + 'eventUpdate' at /secure/cmds/creators/update at line 148 + 'CATCH' at /secure/cmds/creators/update at line 148 + Trace written to /log/catch + /realms/cratylus/area/room/sample_room: Error in update + *Error in loading object '/realms/cratylus/area/room/sample_room' + + + + This output lets you know something is wrong, but + isn't very specific as to exactly what. If you look at your error + log, you probably will see something more detailed and helpful: + + + > %^GREEN%^elog%^RESET%^ + + /log/errors/cratylus: + + /realms/cratylus/area/room/sample_room.c line 10: Undefined variable 'Sample' + /realms/cratylus/area/room/sample_room.c line 10: parse error + + + + Now you can see that the error is my syntax on + line 10. I would then use ed to examine the code, and specifically lines 9 + through 11. It turns out that I forgot to put quotes around the room name, + so the parser tried to use it as a variable, which, of course, it couldn't. + + If the file in question is in /secure, you'd type elog secure , or if + it's in /cmds, elog cmds , and so on. + + + dbxwhere & dbxframe + + Two helpful debugging commands are dbxframe and dbxwhere. Let's + take a look at my broken sample_room.c file. We'll start with dbxwhere, + which lists for us the chain of events that led to the error. The + indivudual steps are called frames. + + > %^GREEN%^dbxwhere%^RESET%^ + *Error in loading object '/realms/cratylus/area/room/sample_room' + Object: /secure/cmds/creators/update at line 148 + + #0: '<function>' at /secure/save/creators/c/cratylus (<function>) at /:0 + #1: 'cmdAll' at /secure/save/creators/c/cratylus (/lib/command.c) at line 84 + #2: 'cmd' at /secure/cmds/creators/update at line 109 + #3: 'eventUpdate' at /secure/cmds/creators/update at line 148 + #4: 'CATCH' at /secure/cmds/creators/update at line 148 + + + The output is similar to the update error we saw above, but in ennumerating the steps, dbxwhere + lets us use dbxframe to get tighter detail on a given error frame: + + > %^GREEN%^dbxframe 4%^RESET%^ + ------ + /secure/cmds/creators/update.c:148 - CATCH(0) + ---------------------------------------------------------------- + if( args == base_name(this_object()) ) { + this_player()->eventPrint("Cannot reload update after destruct.\n" + "It will be reloaded at next reference."); + return 0; + } + => tmp = catch(call_other(args, "???")); + if( !tmp ) { + if(identify(flags ^ U_AUTOMATED) == + "8")this_player()->eventPrint(args + ": Ok"); + return 1; + } else this_player()->eventPrint(args + ": Error in update\n" + tmp); + return 0; + + + We're now looking at the error context for error frame 4. The output of the command shows + us part of the file that was performing the evaluation when the error occurred, and even + points out the offending line using a text arrow: => + + In this particular case, the information is not that helpful. We are being told that + the error occurred while we were using the update command, and it failed at the line + where update does its thing. Duh, we knew that. The elog command was much more helpful. + + Where this kind of tracing comes in handy is when you enounter a runtime error + when you're not updating a file. For example, if I tried to enter that room, rather than + update it, I'd get a big pukey error message and not know why. If you run into an + unexpected error, dbxwhere will help you pinpoint it if elog doesn't provide useful information, + and dbxframe will help detail the source of the problem. + + %^GREEN%^tail%^RESET%^ + + + This is a version of the unix tail command. It displays the last few lines of a file. + This command is important for examining crucial log files: + + %^GREEN%^tail /log/catch%^RESET%^ + %^GREEN%^tail /log/runtime%^RESET%^ + %^GREEN%^tail /log/player_errors%^RESET%^ + + + bk & restore + + These commands aren't so much for debugging as they are for safe coding. Before you + edit a file, it is a very good idea to back it up first. The bk command lets you + quickly and conveniently back up a file before you edit it. When I typed: + + %^GREEN%^bk sample_room%^RESET%^ + + A file with a unique identifying number was created in my bak/ directory. If I + were to type it again, then sample_room.c would get copied again to bak/, with + a new unique number added to the name. + + The number is basically the number of seconds elapsed since January 1, 1970. + Adding this number, we can keep track of which backed up version of a file + is most recent by looking at the name. + + Suppose I edited a file called sample_npc.c. I use bk to back it up, make some changes, + then use bk again, make some more changes, but now it won't update. I don't + feel like debugging, I just need this file working again, so I want to restore from + backup. The sequence of commands would look something like this: + + %^GREEN%^ed sample_npc.c%^RESET%^ + %^GREEN%^bk sample_npc%^RESET%^ + %^GREEN%^ed sample_npc.c%^RESET%^ + %^GREEN%^update sample_npc.c%^RESET%^ + <error occurs here> + %^GREEN%^restore sample_npc%^RESET%^ + + The reason identifying numbers are used is that you can also choose to + restore the second-to-last backup version of a file, and other previous + versions. + The very last backup version is effectively version 0, so it's not + necessary to specify a number. If I wanted to restore the version I backed + up before that one, I would type something like this: + + %^GREEN%^restore sample_npc 1%^RESET%^ + + And if I wanted the version before that one, I'd specify 2 instead of 1, + and so on. + + Please note that this is an intentionally simple system. There are + no menus, no version branches, or diff tracking. The reason for this is + that it is not a versioning system. It is a backup system. It is a convenient + tool to back out of screwups, not a development tool to test file versions. + + diff -c -r --new-file ds1.1/lib/doc/help/creators/ds ds2.1/lib/doc/help/creators/ds *** ds1.1/lib/doc/help/creators/ds Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/ds Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,39 ---- + The dead_souls intermud channel + + There is an internet communication protocol that + allows muds to send and receive information from each other. This + is called the Intermud network, of which there are several + versions and subnets. + + By default, your mud is connected to the Intermud3 + network, or I3 (see intermud.org for specs). On this + network there are numerous channels available: some are + friendly, some are hostile, some are invitation-only, and + some are open to all. + + Unless your admins have disabled intermud, or you + are tightly firewalled, or channels have been restricted, + you probably are listening to a channel called "dead_souls". + This channel exists to allow creators on Dead Souls muds + on the internet to talk, ask questions, share ideas, etc. + + Random chat is not exactly discouraged, but code + questions and discussions always have priority on this + channel. It can be used socially, but its primary purpose + is as a support system for the Dead Souls community. + Accordingly, muds that spam the channel, or subject it + to malicious data or metadata, are likely to be permanently + banned from it, regardless of whether it was the fault of + just one jerk. Messages of an offensive nature also + qualify as bannable material, and this is at the discretion + of the owner of the channel, which is the Dead Souls mud. + + If you need to perform channel testing, please avoid + using the dead_souls channel ( also known as <ds> ) for + this. A special testing channel has been set up for that + purpose. It is called ds_test, and you can add it to + yourself by typing: + + %^GREEN%^call me->AddChannel("ds_test")%^RESET%^ + + diff -c -r --new-file ds1.1/lib/doc/help/creators/editor ds2.1/lib/doc/help/creators/editor *** ds1.1/lib/doc/help/creators/editor Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/editor Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,372 ---- + + + The Ed Primer + --or-- + Your Introduction To The Wonderful World Of Programming With Ed! + + 0. A Prelude: + (How to read the author's peculiar notation) + + In all examples: + + Words in angle brackets <like this> are not to be typed literally, but rather + to be substituted for. For example, '<number>p' could be '4p' or '27p', etc. + [Anything in square brackets] is optional. + <x|y> represents <x> OR <y>, but not both. + > is assumed to be the standard lpmud prompt. + : is assumed to be the ed command mode prompt. + * is assumed to be the ed insert mode prompt. + + --The author/editor + + I. A Beginning: + (The 'ed', 'a', 'i', 'w', and 'q' commands) + + First, the command to enter ed from lpmud can take one of two basic forms: + > ed <filename> + or + > ed <dummy filename>. + + The first is used to edit an existing file. The second is used to create a new + file. The dummy filename can be any string that isn't already the name of a + file. Short strings like 'a' work well for this. + + Once you are in ed, your prompt will become ':'. From this prompt you enter + ed commands. If you are beginning a new file, you can use one of two commands + to enter insert mode: 'a' or 'i'. The difference between these two will become + significant later on. In insert mode, your prompt will become '*'. From here + you type in the body of your file. You can leave insert mode at any time by + typing a single '.' on a line by itself. + + Once you are finished entering your text and have returned to command mode + (':' prompt), you can save your file with the 'w' command, specifying a + filename: + + :w myfile.c + + Then you can use 'q' to exit ed, and return to your normal propmt. + + Summary: + + > ed <file | dummy file> takes you into ed. + 'a' and 'i' in command mode begin insert mode. + ---> Implicit assumtion from now on: all commands will be from command mode + ---> unless it is stated otherwise. + '.' in insert mode returns you to command mode. + 'w <file>' saves your file. + 'q' takes you out of ed. + + + II. Editing existing files: + (The 'ed', 'a', 'c', 'd', 'i', 'l', 'p', 'w', 'z', and '=' commands.) + + To edit an existing file (a reminder from section I), use: + + > ed <filename> + + This again puts you in command mode, with the difference from starting a new + file that there are already lines in the buffer. Use the command '.p' to + see the line you are presently on. + + The command 'p' will print out a line or range of lines. Its syntax is this: + 'p' or '.p'* will print out the line you are presently on. '<number>p' will + print out line number <number>. '<number1>,<number2>p' will print out the + range of lines from <number1> to <number2>. In this case, <number1> must be + less than or equal to <number2>. In both cases, all numbered lines must exist, + or the command will fail. The command 'l' is similar to 'p' in most respects, + except that it also makes visible some 'invisible' characters, like newline + (which shows up as $). Tabs become completely invisible. 'z' will display + 21 lines in 'p' fashion (i.e., ctrl characters remain invisible). 'z' can + be prepended by a line number to start at. + + The command <number> will take you to the line of the same number. + + The commands 'i' and 'a' are the commands introduced in section I. The + difference between these two commands now takes on a significance; 'i' starts + inserting before the line you are presently on, while 'a' starts inserting + after the line you are on. (Use '.' or '.p' to display the line you are on.) + Also, 'i' and 'a' can both be prepended by a <number>, ('<number>i' and + '<number>a'), which sets your present line at <number> before beginning insert + mode. + + The command '=' can be used to discover the number of the line you are on. + + The command 'd' deletes the current line you are on. 'd' can, like 'p' and + 'l', be used with a single line number, or a range of them for arguments. + + The command 'c' is used to change lines. It is essentially similar to 'd' + in its usage, except that instead of leaving you in command mode, you are + put into insert mode, inserting text to 'replace' what was removed. + + Finally, 'w' without being followed by '<file>' will save the file under the + name you began editing it as, provided that that file already existed. + + Footnote: * As a number, '.' refers to the present line; '$' refers to the last + line of the file. + + An example encompassing what we've done so far: + > ed a + :a + *This is line 1. + *This is line @. + *This is line 3. + *This is line 5. + *This is too many lines. + *. + :1,3p + This is line 1. + This is line @. + This is line 3. + := + 3 + :5l + This is too many lines.$ + :5d + :1,$p + This is line 1. + This is line @. + This is line 3. + This is line 5. + :2c + *This is line 2. + *. + :1z + This is line 1. + This is line 2. + This is line 3. + This is line 5. + :4i + This is line 4. + :1,$p + This is line 1. + This is line 2. + This is line 3. + This is line 4. + This is line 5. + :w file.txt + :q + > ls + Total 1 + 1 file.txt + > + + Summary: + + 'p' and 'l' are used to display ranges of lines. 'l' displays some invisible + characters. + 'z' displays 21 lines in 'p' format. + '=' displays the current line number. + 'd' deletes a line. + 'c' changes a line by deleting it and putting you into insert mode. + --As numbers, '.' refers to the present line, and '$' to the last line of the + file. + + III. More Advanced Editing: + (The 's' command) + + The 's' command is used for substitutions. The general format is this: + + :[<number1>[,<number2>]]s<delimiter><pattern><delimiter><sub>[<delimiter>gp] + + The command may look intimidating at first, but it turns out to be one of the + most powerful commands in ed. + + An explanation of all the angle-brackets: + <number1> and <number2> are the range of substitution. If ',<number2>' is + omitted, the range of effect is merely line <number1>. If '<number1>' is also + omitted, the substitution defaults to the present line. + + <delimiter> is simply a character used as a separator. Care should be taken + that '<delimiter>' does not occur in either <pattern> or <sub>. The most + common choices for <delimiter> are '/' and '!', although any character can be + used. + + <pattern> is the string that will be changed. <sub> is the string that it will + be changed to. If <pattern> begins with a '^', that is taken to mean 'beginning + of line.' Similarly, if it ends with '$', it signifies 'end of line.' + + The final optional [gp] are used, respectively, to make the substitution global + throughout the line (instead of just affecting the first occurrence), and to + display the newly-changed line immediately afterwards. Note that g must come + before p, if both are used. + + Some examples: + + :. + This is line nubmer 3. + :s/bm/mb/p <--- Note that '/' is used as the delimiter here. + This is line number 3. + : + + :. + Thsi si line 3. + :s!si!is!p <--- The delimiter here is '!'. + This si line 3. <--- Note that only the 1st occurrence of 'si' was changed + : + + :. + Thsi si line number 3. + :s!si!is!gp <--- Here, the delimiter is '!', again. + This is line number 3. + : + + :3,5p + This is lize 3. + This is lize 4. + This is lize 5. + :3,5sqzqnqp <--- Here, to confuse matters, the delimiter is 'q'. + This is line 3. + This is line 4. + This is line 5. + : + + General notes: + For a global substitution, use: + :1,$s/<pattern>/<sub>/g + + Beware of special characters in <pattern>. '.', '(', ')', '&', '*', '|', '[', + '^', and ']' should all be prepended by backslashes ('\') if they are used. + '\' is, although possible to use in <sub> and <pattern>, very tricky to use. + The author recommends beginners use the 'c' command to do sunstitutions for + this character instead. + + Some of these special characters that can be used in <pattern>: + . Match any character. + x* Match any numbers of x (0 or more). + [abc] Match 'a', 'b' or 'c'. + [0-9] Match any digit 0 - 9. + [a-z] Match any lowercase letter. + [^0-9] Match anything except a digit 0 - 9. + + The & can be used in the replacement to represent the text being replaced. + + Example: + :. + This is a lazy line, lying abed. It is also silly; abcd. + :s/ab.d/ABCD/gp + This is a lazy line, lying ABCD. It is also silly; ABCD. + : + + Example: + :. + This is a long line that is being used to demonstrate a silly example. + :s/l.n./&foo/ + This is a longfoo linefoo that is being used to demonstrate a silly example. + + III-I/II. (3.5, for those who can't figure that out.) Author's Interjection: + (The '<range>' notation) + + What was formerly referred to as <number1>,<number2><command> will, from here + on out, be referred to as <range><commmand>, for the author's typing ease. + Thank you. + + Campus. Still More Advanced Commands, and Related Shortcuts: + (The 'e', 'E', 'f', 'j', 'k', 'Q', 'm', 'r', 't', 'x', and '!' commands) + + The 'e', 'E', and 'r' commands can all be used to read external files into the + buffer. 'e <file>' reads <file> into the buffer, deleting everything in the + buffer. Because it is destructive, the exact buffer contents must be saved + before this command can be executed. 'E <file>' works exactly as 'e <file>', + except that it ignores the saved status of the present buffer. + '<number>r <file>' reads in the contents of <file>, placing them after line + <number>. As usual, if <number> is omitted, it defaults to the current line. + + 'Q' and 'x' can, like 'q', be used to exit ed. 'q' can only be used to exit + ed if the exact contents of the buffer are saved. 'Q' can be used to exit + regardless of the saved status of the buffer. 'x' saves the buffer to the + default file name and exits ed. Note that if there is no default file name, + 'x' will fail. + + '<range>j' will join all of the lines in <range> together into one line. + + '<number>k<marker>' will assign <marker> to line <number>. <marker> can be + any lowercase letter. A line marked is referred to as "'<marker>". For + example, the commands: + :5kd + :1,'dp + will mark line 5 as "d" and then print out lines 1-5. + + 'f <file>' sets the default name of the file (used for the 'w' and 'x' + commands) to <file>. + + 't' and 'm' are both used to move sections of text. The format is: + :<range>t|m<number> + where <range> is the text to be moved, and <number> the line it is to be + inserted after. 't' is 'transfer' and leaves a copy of the text to be moved + at the original site; it is basically a 'copy' command. 'm' is 'move' and + moves the text from its original site to its new site. + + '!' is used to execute lpmud commands from within ed, and can be used in either + the command or the insert mode. For example: + :!'Wait, please; I'm in ed. + Guest says: But I want to talk. + :i + *!'I said wait, please. + * + + + A summary: + 'e', 'E', and 'r' are used to retrieve external files to the buffer. + 'Q' is used to exit, regardless of save status. + 'x' is used to save and exit in one step. + 'f' changes the default name of the file. + 'j' joins lines together. + 'k' marks lines. + 't' is used to transfer, or copy lines. + 'm' is used to move lines. + '!' in command and insert modes, is used to execute an lpmud command. + + Campus. Seek, and Ye Shall Find + (The 'g', 'v', '?', and '/' commands) + + '/' and '?' are used to find expressions in the buffer. '/<string>' does a + forward search for <string>, while '?<string>' does a backward search. + '/' and '?' with no arguments default to the previous argument. If no argument + was given prior, an error occurs. + + 'g' and 'v' use similar formats for operation: + :<range>g|v/<string>/<command> + + Both 'g' and 'v' search through <range> for lines that contain <string>. + 'g' executes <command> on all lines in <range> that contain <string>, while + 'v' executes <command> on all lines that do not contain <string>. + + <command> may be one of the following commands: 's', 'l', 'p', 'd', 'm', or + 'r'. Arguments for these commands work normally. + + '/' and '?' may be used similarly to operate on the first occurrence of + <string> found. For example: + :/foo/s/x/ox/gp + + will replace all instances of 'x' on the next line containing + 'foo' with 'ox' and set your current line there. Similarly, + :?bar?= + will give you the + number of the first previous line containing the string 'bar', and set your + current line there. + Exapmles: + + :1,$p + This is a test. + This is line two of the test. + There are more than two lines. + This is the last line. + :1,$g/two/l + This is line two of the test.$ + There are more than two lines.$ + :1,$v/two/d + :1,$p + This is line two of the test. + There are more than two lines. + :?test + This is line two of the test. + :.p + This is line two of the test. + :/There + There are more than two lines. + :Q + > + + --Mishael, author/editor. + David "Mishael" Green + dgreen@jarthur.claremont.edu diff -c -r --new-file ds1.1/lib/doc/help/creators/emotes ds2.1/lib/doc/help/creators/emotes *** ds1.1/lib/doc/help/creators/emotes Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/emotes Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,122 ---- + Emote Name: A name for the emote (Example, "slap") + + Error Message: An error for emotes that don't match the parse rules (Example, "Slap who?") + + Parse Rule: A rule for the parser to see who to slap (Example, "LVS STR" to allow the user to "slap shadyman hard") + + Verbs: Verbs this applies to (usually just the emote name) + + Message: What gets displayed when the emote happens. (Example, "$agent_name $agent_verb $target_name.") + + Adverbs: One of 4 choices: + 1) Any special adverbs that apply to this emote that don't exist already, in a comma delimited list + 2) '-', to allow only preselected adverbs to be used + 3) 'none', to allow no adverbs to be used + 4) '*', to allow any word to be used + + + Shadyman smiles sweetly at Kira + Emote Name: smile + Error Msg: none + Parse Rule: at LVS,LVS + Verbs: smile + Message: $agent_name $agent_verb $adverb at $target_name. + Adverbs: * + + Once you have that one rule done, you can add more by using "addemote -add" + You can also edit rules for an emote by using "addemote -edit" + You can remove a rule by using "removeemote [emotename] [rulename]" (see "addemote -edit" for rules in the emote, ie: "at LIV STR") + Removing an entire emote is done by "removeemote" + + + <COMMANDS LIST> + + Command You See Target Sees Room Sees + ------- ------- ----------- --------- + $agent_verb smile Smile Smile + $agent_name you Shadyman Shadyman + $agent_nominative you he/she he/she + $agent_objective you him/her/them him/her/them + $agent_possessive_noun your Shadyman's Shadyman's + $agent_possessive your his/hers his/hers + $agent_reflexive yourself himself/herself himself/herself + $target_verb smiles smiles smiles + $target_name Kira you Kira + $target_nominative he/she/they you he/she/they + $target_objective him/her/them you him/her/them + $target_possessive_noun Kira's your Kira's + $target_possessive his/hers/theirs your his/hers/theirs + $target_reflexive him-/her-/themselves yourself him-/her-/themselves + $adverb happily happily happily + + + <SAMPLE EMOTE CREATION> + + Let's add the emote Snicker. Just simply, an emote that says "You snicker" when you type "snicker". + Since it will have no arguments, you don't need to add a parser rule or adverbs. + + > addemote snicker + Enter error message: Snicker at whom? + Enter a parser rule for snicker: + Enter the verbs: snicker + Enter message: $agent_name $agent_verb. + Enter adverbs: + Emote 'snicker' added. + + Now let's add a rule to 'snicker' to make it more useful. Let's add "snicker at [someone]", with a living person as a target. + Since there will still be no adverbs, we'll leave the adverbs blank, but we will be using the parser rule, because we want to snicker AT someone. + + > addemote -add + Enter emote name: snicker + Enter error message: Snicker at whom? + Enter a parser rule for snicker: at LIV + Enter the verbs: snicker + Enter message: $agent_name $agent_verb at $target_name. + Enter adverbs: + Emote 'snicker' added. + + Now let's add the ability to use adverbs with our 'snicker' emotion, like 'snicker at shadyman loudly' and 'snicker loudly at shadyman'. Note we'll be adding two rules at once. + If you want your users to use their own (non-approved) adverbs or strings of text, you should put '*' in the adverbs section. Otherwise, put '-' to use only pre-approved adverbs. + + > addemote -add + Enter emote name: snicker + Enter error message: Snicker at whom? + Enter a parser rule for snicker: at LIV STR,STR at LIV + Enter the verbs: snicker + Enter message: $agent_name $agent_verb at $target_name $adverb. + Enter adverbs: * + Emote 'snicker' added. + + Go ahead and experiment with various types of parsing rules, using LIV, STR, LVS, and prepositions such as 'with', 'as', 'like', etc. + + <SAMPLE EMOTE IN "addemote -edit" MODE> + Emote: boggle + Error Message: Boggle! + Rules: + [1] "LIV STR": $agent_name $agent_verb $adverb at $target_name. + Adverbs: - + + [2] "at LIV": $agent_name $agent_verb at $target_name. + Adverbs: + + [3] "STR at LIV": $agent_name $agent_verb $adverb at $target_name. + Adverbs: - + + [4] "STR": $agent_name $agent_verb $adverb. + Adverbs: - + + [5] "LIV": $agent_name $agent_verb at $target_name. + Adverbs: + + [6] "at LIV STR": $agent_name $agent_verb $adverb at $target_name. + Adverbs: - + + [7] "STR LIV": $agent_name $agent_verb $adverb at $target_name. + Adverbs: - + + [8] "": $agent_name $agent_verb. + Adverbs: + + Revisions: + ---------- + Document Created: [Shadyman, Mar 16, 2006] diff -c -r --new-file ds1.1/lib/doc/help/creators/force ds2.1/lib/doc/help/creators/force *** ds1.1/lib/doc/help/creators/force Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/force Tue Jul 11 18:36:11 2006 *************** *** 0 **** --- 1,4 ---- + Syntax: <force LIVING SOMETHING> + <force LIVING to DO SOMETHING> + Allows you to command some living things to do + your bidding. diff -c -r --new-file ds1.1/lib/doc/help/creators/mappings ds2.1/lib/doc/help/creators/mappings *** ds1.1/lib/doc/help/creators/mappings Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/mappings Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,60 ---- + Dead Souls and Mappings + + A mapping is an organization of data that makes it possible to associate + data elements together in a human-understandable way. + + For a builder with no coding experience, mappings can be a challenge to + understand. However, you must grasp at least the very basics of this data type in order to be an effective builder. + + The Dead Souls mudlib has three kinds of objects that normally have other + objects inside of them: NPC's, rooms, and containers. When the mud loads + one of these, often they are intended to have stuff inside them already, such + as a teasure chest with jewels, an orc with an axe, or a room with an orc + guarding a treasure chest. + + In such a circumstance, each of these objects is loaded from a file that + contains information about the contents of the object. This is called the + object's inventory, and it is determined by the SetInventory directive in that + file. + + An example of a room's SetInventory directive might look a little like this: + + SetInventory( ([ + "/domains/town/npc/fighter" : 1, + "/domains/town/npc/orc" : "growl", + "/domains/town/obj/chest" : 1, + ]) ); + + You can tell it's a mapping right away from the square brackets: [ ]. + + What this mapping does is identify a fighter, orc, and chest as objects to + be put into the room when it is loaded. If we wanted 2 fighters, we would have + put a 2 instead of a 1 there. + + What the "growl" value does is provide that orc with a command to perform + when it appears. You could just have a number there, to specify the number + of orcs desired. + + That's it. It's that simple. A mapping consists of pairs of data, separated + by a colon (the : symbol). The part to the left is called a key, and the + part to the right is called the value. + + A mapping can contain more than one of these pairs, each separated from + the other by a comma. + + As a non-coding builder, what you need to know is that when the creation system + asks you for a key, it is possible for keys to have multiple values, like + this: + + ({"room","here","area"}) : "This area looks very nice." + + In this example, the mapping element is part of the SetItems directive. + + When you modify a room's description items, you will be asked to enter keys until you are + done. This allows you to enter multiple words that respond in the same + way. For example, "examine wall" and "examine concrete wall" should both + provide the same description. + + However, in the case of inventory, only one key is valid, so make sure you + only enter one. + diff -c -r --new-file ds1.1/lib/doc/help/creators/messaging ds2.1/lib/doc/help/creators/messaging *** ds1.1/lib/doc/help/creators/messaging Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/messaging Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,122 ---- + The best way to do messaging these days is through a single simul + efun: + send_message() + + varargs void send_message(mixed verb, string message, object agent, + mixed targets, mixed observers, mapping special); + + Example: + + send_message("cast", "$agent_name $agent_verb $agent_possessive pole in " + "order to fish.", this_player(), 0, + environment(this_player())); + + replaces BOTH: + this_player()->eventPrint("You cast your pole in order to fish."); + environment(this_player())->eventPrint(this_player()->GetName() + + " casts " + + possessive(this_player()) + + " pole in order to fish.", + this_player()); + + AND + the write()/say() equivalent. + + First, let's go over the arguments to send_message(): + + * mixed verb + This will normally be a single verb that you want conjugated in the + sentence for different viewers. In the above example, "cast" needed + to be displayed as "cast" for the caster and "casts" for observers. + In some sentences, you made need more than one verb. Take for + example: + "You rock and roll." + "Descartes rocks and rolls." + + This is done by using an array instead of a single string. The rock + and roll example would look like: + send_message(({ "rock", "roll" }), "$agent_name $agent_verb and $agent_verb.", + this_player(), 0, environment(this_player())); + + For each verb mentioned in the message, there must be a corresponding + verb in the verb array. + + The verb should be expressed in second person singular format. + + * string message + A message containing tokens that will be replaced when the message is + displayed. Campusalid tokens are: + $agent_name - replaced with the name of the agent + $agent_nominative - replaced with the nominative pronoun for the + agent (he, she, or it) + $agent_objective - replaced with the objective pronoun for the agent + $agent_possessive - the agent's possessive pronoun + $agent_possessive_noun - the possessive version of the agent's name + $agent_reflexive - the reflexive pronoun for the agent + + For each of the agent tokens, there also exist target tokens: + $target_name, $target_nominative, $target_objective, + $target_possessive, $target_possessive_noun, $target_reflexive + + And finally, $agent_verb and $target_verb. + + You have to associate a verb with a person so that the system knows + how to conjugate the verb for each viewer. Take for example: + + "Horace is struck by Descartes' sword." + "Descartes strikes Horace." + + In both instances, Descartes is the agent. The verb in the first + sentence is "are" and in the second sentence "strike". But the + subject of the sentence in the first sentence is NOT the agent. It is + the target. The corresponding send_message() would look like: + + send_messages("are", "$target_name $target_verb struck by " + "$agent_possessive_noun sword.", this_player(), enemy, + environment(this_player()); + + send_messages("strike", "$agent_name $agent_verb $target_name.", + this_player(), enemy, environment(this_player())); + + Using just this knowledge, you can now send something like: + send_message(({ "miss", "sidestep" }), "$agent_name $agent_verb " + "$target_name as $target_nominative $target_verb " + "$agent_possessive_noun attack.", this_player(), enemy, + environment(this_player())); + This will show me: + "You miss Horace as he sidesteps your attack." + And Horace: + "Descartes misses you as you sidestep Descartes' attack." + And other people in the room: + "Descartes misses Horace as he sidesteps Descartes' attack." + + All done in a single line of code. + + * object agent + The agent is the person who is considered to be doing the action. It + can only be a single object. + + * mixed targets + You can have one or more targets. Traditionally, you will have only + one. The above examples have dealt with a single target. You could + however have: + send_message("get", "$agent_name $agent_verb $target_name.", + this_player(), all_inventory(environment(this_player())), + environment(this_player())); + To show: + "You get two swords and a fish." + And to the room: + "Descartes gets two swords and a fish." + + On a completely uninteresting side-note, the message also gets sent to + the two swords and a fish. + + * mixed observers + Any objects which might be observing this action. It is most often + the room in which the agents and object are located. + + * mapping special + Some library objects may wish to add their own tokens to the token + list for parsing. For examples, spells send ([ "$limb" : "right hand"]) + + You will almost never need that last argument. diff -c -r --new-file ds1.1/lib/doc/help/creators/plan ds2.1/lib/doc/help/creators/plan *** ds1.1/lib/doc/help/creators/plan Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/plan Fri Jul 7 19:41:41 2006 *************** *** 0 **** --- 1,7 ---- + Your plan file is the extra information others see when + they finger you, usually listing what your projects are + and what you've been up to. To modify your plan, + edit the .plan file in your home directory. For example, + + cd + ed .plan diff -c -r --new-file ds1.1/lib/doc/help/creators/profile ds2.1/lib/doc/help/creators/profile *** ds1.1/lib/doc/help/creators/profile Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/profile Fri Jul 7 19:41:41 2006 *************** *** 0 **** --- 1,11 ---- + Your profile is a file that contains a list of + instructions. When you log in, the mud will force + you to execute those commands. To modify what those + "startup commands" are, edit the .profile file in + your home directory. For example: + + cd + ed .profile + + Note that the mud cannot force you to do + certain things as a security measure. diff -c -r --new-file ds1.1/lib/doc/help/creators/qcs ds2.1/lib/doc/help/creators/qcs *** ds1.1/lib/doc/help/creators/qcs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/qcs Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,824 ---- + %^CYAN%^ What's the QCS? %^RESET%^ + + + QCS stands for Quick Creation System. The QCS is a + series of commands and modules that lets you create stuff + easily and quickly. Before the QCS, if you wanted to make + an orc, you would edit the text file by hand, or copy + a template file and use an editor to manually change the + lines you needed to modify. This could be a tiresome + process, as the standard editor can be a bit awkward, and + making dozens of objects this way could be real torture for + beginners. + + The QCS changes all of that. Rather than use an + editor to meodify files, the QCS gives you commands that + permit you to modify objects on the fly. This means that + orc creation for example could involve just the following + simple steps (please note "npc" is another word for "mob"): + + %^GREEN%^ create npc new_orc %^RESET%^ + + %^GREEN%^ modify npc name orc %^RESET%^ + + %^GREEN%^ modify orc short a mean-looking orc %^RESET%^ + + %^GREEN%^ modify orc long A typical orc: nasty, brutish, and short. %^RESET%^ + + %^GREEN%^ modify orc race orc %^RESET%^ + + And that's it. All your modifications automatically + get written to new_orc.c (usually in your area directory), + and you now have an npc you can add to a room. Adding things + to rooms is just as easy. Creating weapons, armor, and other + objects is done the same way. + + For complete details and examples, read the + QCS chapters in the Creators Manual. The QCS section starts + in chapter 31. + + + This is a log of the creation of some items using the Dead Souls creation system. It has + not been modified in any way except to highlight the command lines and adding comments. + + + + Dead Souls has been up for 2h 25m 38s. + %^GREEN%^ home %^RESET%^ + /realms/testycre/workroom + Testycre's workroom [e,d] + You are standing in the workroom of the mighty Testycre! + You may return to the Creators' Hall by going down. + A sample room is east. + There is a sign here you can read. + There is a sheet here you can read. + A wooden chest is here. + + + %^GREEN%^ e %^RESET%^ + /realms/testycre/area/room/sample_room + Sample Room [w] + This is a room you can use as a template. + A simple table is here. + A fighter is standing here. + + //// This is the standard sample room. We're about to create a new room to the east of it. + %^GREEN%^ create room east test1 %^RESET%^ + It appears you have write access to this area. + It's a null mapping + Indenting file... + "/tmp/indent.1134436511.tmp.dat" 20 lines 330 bytes + Exit from ed. + + You wave your hand, and a new exit appears. + You begin uttering a magical incantation. + Indenting file... + "/tmp/indent.1134436511.tmp.dat" 27 lines 543 bytes + Exit from ed. + + Indenting file... + "/tmp/indent.1134436511.tmp.dat" 27 lines 544 bytes + Exit from ed. + + %^GREEN%^ e %^RESET%^ + /realms/testycre/area/room/test1 + Copy of /realms/testycre/area/room/sample_room.c [w] + This is a room you can use as a template. + A simple table is here. + A fighter is standing here. + + //// We go into the new room and see it is a copy of the old one. Let's change the short description to avoid confusion: + %^GREEN%^ modify here short Room One %^RESET%^ + Indenting file... + "/tmp/indent.1134436526.tmp.dat" 27 lines 515 bytes + Exit from ed. + + //// We don't need the fighter from the other room here, so we remove him from this new room's inventory. + %^GREEN%^ delete fighter %^RESET%^ + Indenting file... + "/tmp/indent.1134436532.tmp.dat" 26 lines 507 bytes + Exit from ed. + + /realms/testycre/area/room/test1: Ok + /realms/testycre/area/room/test1 + Room One [w] + This is a room you can use as a template. + A simple table is here. + + + SetInventory modification complete. + //// Let's make another room. + %^GREEN%^ create room east test2 %^RESET%^ + It appears you have write access to this area. + It's a null mapping + Indenting file... + "/tmp/indent.1134436578.tmp.dat" 20 lines 324 bytes + Exit from ed. + + You wave your hand, and a new exit appears. + You begin uttering a magical incantation. + Indenting file... + "/tmp/indent.1134436578.tmp.dat" 27 lines 557 bytes + Exit from ed. + + Indenting file... + "/tmp/indent.1134436578.tmp.dat" 27 lines 525 bytes + Exit from ed. + + %^GREEN%^ e %^RESET%^ + /realms/testycre/area/room/test2 + Copy of /realms/testycre/area/room/test1.c [w] + This is a room you can use as a template. + A simple table is here. + + + %^GREEN%^ modify here short Room 2 %^RESET%^ + Indenting file... + "/tmp/indent.1134436590.tmp.dat" 26 lines 499 bytes + Exit from ed. + + %^GREEN%^ modify here long This is the second test room. %^RESET%^ + Indenting file... + "/tmp/indent.1134436608.tmp.dat" 26 lines 487 bytes + Exit from ed. + + //// We don't need that table here. + %^GREEN%^ delete table %^RESET%^ + Indenting file... + "/tmp/indent.1134436612.tmp.dat" 25 lines 447 bytes + Exit from ed. + + /realms/testycre/area/room/test2: Ok + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + SetInventory modification complete. + + //// We look at the file contents to make sure what we're doing really is being written into the room's code: + %^GREEN%^ more here %^RESET%^ + #include <lib.h> + #include "/realms/testycre/customdefs.h" + + inherit LIB_ROOM; + + static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Room 2"); + SetLong("This is the second test room."); + SetExits(([ + "west" : "/realms/testycre/area/room/test1", + ])); + + SetItems( ([ + "template" : "That's what this is.", + ]) ); + + SetInventory(([ + ])); + } + + void init(){ + ::init(); + } + + //// Let's make a new guy. "guy" will be the filename. + %^GREEN%^ create npc guy %^RESET%^ + I'm going to go with the appropriate area directory: + /realms/testycre/area/npc/guy.c + You wave your hand mysteriously and a generic npc materializes! + %^GREEN%^ l %^RESET%^ + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + A generic npc is standing here. + + //// This is the first thing you should do, in order to avoid confusion. + %^GREEN%^ modify npc name guy %^RESET%^ + Indenting file... + "/tmp/indent.1134436801.tmp.dat" 15 lines 417 bytes + Exit from ed. + + %^GREEN%^ modify npc id %^RESET%^ + This setting takes multiple values. If you have no more values to enter, then + enter a dot on a blank line. To cancel, enter a single q on a blank line. + You may now enter the next value. So far, it is blank. + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ dude %^RESET%^ + You may now enter the next value. So far, we have: ({ "dude" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ fellow %^RESET%^ + You may now enter the next value. So far, we have: ({ "dude", "fellow" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ fella %^RESET%^ + You may now enter the next value. So far, we have: ({ "dude", "fellow", "fella" + }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ . %^RESET%^ + Entries complete. Final array is: ({ "dude", "fellow", "fella" }) + Indenting file... + "/tmp/indent.1134436831.tmp.dat" 19 lines 442 bytes + Exit from ed. + + /realms/testycre/tmp/guy1134436805: Ok + /realms/testycre/area/npc/guy: Ok + SetId modification complete. + %^GREEN%^ modify guy short The Dude %^RESET%^ + Indenting file... + "/tmp/indent.1134436855.tmp.dat" 19 lines 437 bytes + Exit from ed. + + %^GREEN%^ modify guy long This is just some random guy. %^RESET%^ + Indenting file... + "/tmp/indent.1134436904.tmp.dat" 19 lines 408 bytes + Exit from ed. + + %^GREEN%^ modify guy adj %^RESET%^ + This setting takes multiple values. If you have no more values to enter, then + enter a dot on a blank line. To cancel, enter a single q on a blank line. + You may now enter the next value. So far, it is blank. + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ just some %^RESET%^ + You may now enter the next value. So far, we have: ({ "just some" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ random %^RESET%^ + You may now enter the next value. So far, we have: ({ "just some", "random" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ some %^RESET%^ + You may now enter the next value. So far, we have: ({ "just some", "random", + "some" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ . %^RESET%^ + Entries complete. Final array is: ({ "just some", "random", "some" }) + Indenting file... + "/tmp/indent.1134436924.tmp.dat" 19 lines 402 bytes + Exit from ed. + + /realms/testycre/tmp/guy1134436912: Ok + /realms/testycre/area/npc/guy: Ok + SetAdjectives modification complete. + %^GREEN%^ l %^RESET%^ + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + The Dude is standing here. + + + %^GREEN%^ about dude %^RESET%^ + /realms/testycre/area/npc/guy.c + + #include <lib.h> + + inherit LIB_SENTIENT; + + static void create() { + sentient::create(); + SetKeyName("guy"); + SetAdjectives( ({"just some", "random", "some"}) ); + SetId( ({"dude", "fellow", "fella"}) ); + SetShort("The Dude"); + SetLong("This is just some random guy."); + SetLevel(1); + SetRace("human"); + SetClass("explorer"); + SetGender("male"); + } + void init(){ + ::init(); + + //// Now a weapon for our new guy. "hammer" is the filename. + %^GREEN%^ create weapon hammer %^RESET%^ + I'm going to go with the appropriate area directory: + /realms/testycre/area/weap/hammer.c + You wave your hand mysteriously and a generic weapon materializes! + %^GREEN%^ modify weapon id hammer %^RESET%^ + This setting takes multiple values. If you have no more values to enter, then + enter a dot on a blank line. To cancel, enter a single q on a blank line. + You may now enter the next value. So far, we have: ({ "hammer" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ warhammer %^RESET%^ + You may now enter the next value. So far, we have: ({ "hammer", "warhammer" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ . %^RESET%^ + Entries complete. Final array is: ({ "hammer", "warhammer" }) + Indenting file... + "/tmp/indent.1134437181.tmp.dat" 19 lines 453 bytes + Exit from ed. + + /realms/testycre/tmp/hammer1134437165: Ok + /realms/testycre/area/weap/hammer: Ok + SetId modification complete. + %^GREEN%^ modify weapon name hammer %^RESET%^ + There is no weapon here. + %^GREEN%^ l %^RESET%^ + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + A generic weapon is here. + The Dude is standing here. + + //// I accidentally changed the id before the name. Oops! Easy enough to fix: + %^GREEN%^ modify hammer name hammer %^RESET%^ + Indenting file... + "/tmp/indent.1134437205.tmp.dat" 22 lines 474 bytes + Exit from ed. + + %^GREEN%^ about hammer %^RESET%^ + /realms/testycre/area/weap/hammer.c + + #include <lib.h> + #include <damage_types.h> + #include <vendor_types.h> + + inherit LIB_ITEM; + + static void create() { + item::create(); + SetKeyName("hammer"); + SetId( ({"hammer", "warhammer"}) ); + SetAdjectives( ({ "generic" })); + SetShort("a generic weapon"); + SetLong("A weapon of indeterminate proportions."); + SetMass(50); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(BLADE); + SetWeaponType("blade"); + + } + void init(){ + ::init(); + } + %^GREEN%^ modify hammer damagetype blunt %^RESET%^ + Indenting file... + "/tmp/indent.1134437392.tmp.dat" 22 lines 474 bytes + Exit from ed. + + %^GREEN%^ modify hammer weapontype blunt %^RESET%^ + Indenting file... + "/tmp/indent.1134437398.tmp.dat" 22 lines 474 bytes + Exit from ed. + + %^GREEN%^ modify hammer mass 700 %^RESET%^ + Indenting file... + "/tmp/indent.1134437414.tmp.dat" 22 lines 475 bytes + Exit from ed. + + %^GREEN%^ modify hammer hands 2 %^RESET%^ + Indenting file... + "/tmp/indent.1134437422.tmp.dat" 23 lines 492 bytes + Exit from ed. + + //// Let's see if all that stuff really did go into the file: + %^GREEN%^ about hammer %^RESET%^ + /realms/testycre/area/weap/hammer.c + + #include <lib.h> + #include <damage_types.h> + #include <vendor_types.h> + + inherit LIB_ITEM; + + static void create() { + item::create(); + SetKeyName("hammer"); + SetId( ({"hammer", "warhammer"}) ); + SetAdjectives( ({ "generic" })); + SetShort("a generic weapon"); + SetLong("A weapon of indeterminate proportions."); + SetHands(2); + SetMass(700); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(BLUNT); + + SetWeaponType("blunt"); + } + void init(){ + ::init(); + } + %^GREEN%^ modify hammer short a heavy war hammer %^RESET%^ + Indenting file... + "/tmp/indent.1134437450.tmp.dat" 23 lines 494 bytes + Exit from ed. + + %^GREEN%^ modify hammer long This is an extremely large and heavy hammer designed to be wielded in both hands and used to hurt people very badly indeed. %^RESET%^ + Indenting file... + "/tmp/indent.1134437509.tmp.dat" 23 lines 579 bytes + Exit from ed. + + %^GREEN%^ modify hammer adj %^RESET%^ + This setting takes multiple values. If you have no more values to enter, then + enter a dot on a blank line. To cancel, enter a single q on a blank line. + You may now enter the next value. So far, it is blank. + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ large %^RESET%^ + You may now enter the next value. So far, we have: ({ "large" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ heavy %^RESET%^ + You may now enter the next value. So far, we have: ({ "large", "heavy" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ war %^RESET%^ + You may now enter the next value. So far, we have: ({ "large", "heavy", "war" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ . %^RESET%^ + Entries complete. Final array is: ({ "large", "heavy", "war" }) + Indenting file... + "/tmp/indent.1134437531.tmp.dat" 23 lines 592 bytes + Exit from ed. + + /realms/testycre/tmp/hammer1134437521: Ok + /realms/testycre/area/weap/hammer: Ok + SetAdjectives modification complete. + %^GREEN%^ about hammer %^RESET%^ + /realms/testycre/area/weap/hammer.c + + #include <lib.h> + #include <damage_types.h> + #include <vendor_types.h> + + inherit LIB_ITEM; + + static void create() { + item::create(); + SetKeyName("hammer"); + SetAdjectives( ({"large", "heavy", "war"}) ); + SetId( ({"hammer", "warhammer"}) ); + SetShort("a heavy war hammer"); + SetLong("This is an extremely large and heavy hammer designed to be wielded + in both hands and used to hurt people very badly indeed."); + SetHands(2); + SetMass(700); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(BLUNT); + + SetWeaponType("blunt"); + } + void init(){ + ::init(); + } + + //// It's a pretty heavy hammer, so let's make sure our guy can wield it. + %^GREEN%^ modify guy level 10 %^RESET%^ + Indenting file... + "/tmp/indent.1134437557.tmp.dat" 19 lines 403 bytes + Exit from ed. + + //// With this simple command we add the hammer to the permanent inventory of our guy. + %^GREEN%^ add hammer to guy %^RESET%^ + ob2: /realms/testycre/area/npc/guy.c + ob: /realms/testycre/area/weap/hammer.c + Please enter a command for the NPC to perform with this item. If you have no + such command to enter, enter the number of these items you want to add: + %^GREEN%^ wield hammer %^RESET%^ + Indenting file... + "/tmp/indent.1134437569.tmp.dat" 22 lines 489 bytes + Exit from ed. + + /realms/testycre/area/npc/guy: Ok + Guy wields a heavy war hammer. + SetInventory modification complete. + %^GREEN%^ exa guy %^RESET%^ + This is just some random guy. + The male human is in top condition. + Guy is carrying: + A heavy war hammer (wielded in left hand and right hand) + + %^GREEN%^ about guy %^RESET%^ + /realms/testycre/area/npc/guy.c + + #include <lib.h> + + inherit LIB_SENTIENT; + + static void create() { + sentient::create(); + SetKeyName("guy"); + SetAdjectives( ({"just some", "random", "some"}) ); + SetId( ({"dude", "fellow", "fella"}) ); + SetShort("The Dude"); + SetLong("This is just some random guy."); + SetInventory(([ + "/realms/testycre/area/weap/hammer" : "wield hammer", + ])); + SetLevel(10); + SetRace("human"); + SetClass("explorer"); + SetGender("male"); + + } + void init(){ + ::init(); + } + + //// Making armor is just as easy: + %^GREEN%^ create armor helmet %^RESET%^ + I'm going to go with the appropriate area directory: + /realms/testycre/area/armor/helmet.c + You wave your hand mysteriously and generic armor materializes! + %^GREEN%^ modify armor name helmet %^RESET%^ + Indenting file... + "/tmp/indent.1134437645.tmp.dat" 18 lines 483 bytes + Exit from ed. + + %^GREEN%^ modify helmet id %^RESET%^ + This setting takes multiple values. If you have no more values to enter, then + enter a dot on a blank line. To cancel, enter a single q on a blank line. + You may now enter the next value. So far, it is blank. + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ helm %^RESET%^ + You may now enter the next value. So far, we have: ({ "helm" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ headgear %^RESET%^ + You may now enter the next value. So far, we have: ({ "helm", "headgear" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ cover %^RESET%^ + You may now enter the next value. So far, we have: ({ "helm", "headgear", + "cover" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ . %^RESET%^ + Entries complete. Final array is: ({ "helm", "headgear", "cover" }) + Indenting file... + "/tmp/indent.1134437661.tmp.dat" 22 lines 535 bytes + Exit from ed. + + /realms/testycre/tmp/helmet1134437649: Ok + /realms/testycre/area/armor/helmet: Ok + SetId modification complete. + %^GREEN%^ modify helmet short a horned viking helmet %^RESET%^ + Indenting file... + "/tmp/indent.1134437692.tmp.dat" 22 lines 544 bytes + Exit from ed. + + %^GREEN%^ modify helmet long Vikings didn't really wear horned helmets into combat, but this one does look formidable with its large bull horns and thick iron construction. It should prove very protective. %^RESET%^ + Indenting file... + "/tmp/indent.1134437772.tmp.dat" 22 lines 666 bytes + Exit from ed. + + %^GREEN%^ modify helmet adj %^RESET%^ + This setting takes multiple values. If you have no more values to enter, then + enter a dot on a blank line. To cancel, enter a single q on a blank line. + You may now enter the next value. So far, it is blank. + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ iron %^RESET%^ + You may now enter the next value. So far, we have: ({ "iron" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ thick %^RESET%^ + You may now enter the next value. So far, we have: ({ "iron", "thick" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ viking %^RESET%^ + You may now enter the next value. So far, we have: ({ "iron", "thick", "viking" + }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ horned %^RESET%^ + You may now enter the next value. So far, we have: ({ "iron", "thick", "viking", + "horned" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ formidable %^RESET%^ + You may now enter the next value. So far, we have: ({ "iron", "thick", "viking", + "horned", "formidable" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ protective %^RESET%^ + You may now enter the next value. So far, we have: ({ "iron", "thick", "viking", + "horned", "formidable", "protective" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ . %^RESET%^ + Entries complete. Final array is: ({ "iron", "thick", "viking", "horned", + "formidable", "protective" }) + Indenting file... + "/tmp/indent.1134437802.tmp.dat" 22 lines 722 bytes + Exit from ed. + + /realms/testycre/tmp/helmet1134437782: Ok + /realms/testycre/area/armor/helmet: Ok + SetAdjectives modification complete. + %^GREEN%^ about helmet %^RESET%^ + /realms/testycre/area/armor/helmet.c + + #include <lib.h> + #include <armor_types.h> + #include <damage_types.h> + inherit LIB_ARMOR; + + static void create(){ + armor::create(); + SetKeyName("helmet"); + SetAdjectives( ({"iron", "thick", "viking", "horned", "formidable", + "protective"}) ); + SetId( ({"helm", "headgear", "cover"}) ); + SetShort("a horned viking helmet"); + SetLong("Vikings didn't really wear horned helmets into combat, but this + one does look formidable with its large bull horns and thick iron construction. + It should prove very protective."); + SetMass(50); + SetDamagePoints(100); + SetArmorType(A_BODY_ARMOR); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); + + } + void init(){ + ::init(); + } + %^GREEN%^ modify helmet armortype helmet %^RESET%^ + Indenting file... + "/tmp/indent.1134437818.tmp.dat" 22 lines 718 bytes + Exit from ed. + + %^GREEN%^ modify helmet mass 200 %^RESET%^ + Indenting file... + "/tmp/indent.1134437830.tmp.dat" 22 lines 719 bytes + Exit from ed. + + %^GREEN%^ modify helmet protection %^RESET%^ + Your armor can protect against one or more of the following types of damage: + blunt, blade, knife, water, shock, cold, heat, gas, acid, magic, poison, + disease, trauma, .. + + Please enter which ones your armor should protect from, one at a time. + When you are done, please type a dot on a blank line. + %^GREEN%^ blunt %^RESET%^ + You may now enter the next value. So far, we have: ({ "blunt" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ blade %^RESET%^ + You may now enter the next value. So far, we have: ({ "blunt", "blade" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ knife %^RESET%^ + You may now enter the next value. So far, we have: ({ "blunt", "blade", "knife" + }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ trauma %^RESET%^ + You may now enter the next value. So far, we have: ({ "blunt", "blade", "knife", + "trauma" }) + If you're done entering values, enter a dot on a blank line. + %^GREEN%^ . %^RESET%^ + Protections list complete. + Please enter the protection value for: BLUNT + %^GREEN%^ 15 %^RESET%^ + Please enter the protection value for: BLADE + %^GREEN%^ 20 %^RESET%^ + Please enter the protection value for: KNIFE + %^GREEN%^ 25 %^RESET%^ + Please enter the protection value for: TRAUMA + %^GREEN%^ 10 %^RESET%^ + This is where the mapping gets sent somewhere. + ProtectionsMap is: ([ "BLADE" : 20, "BLUNT" : 15, "TRAUMA" : 10, "KNIFE" : 25 ]) + Indenting file... + "/tmp/indent.1134437901.tmp.dat" 23 lines 750 bytes + Exit from ed. + + %^GREEN%^ about helmet %^RESET%^ + /realms/testycre/area/armor/helmet.c + + #include <lib.h> + #include <armor_types.h> + #include <damage_types.h> + inherit LIB_ARMOR; + + static void create(){ + armor::create(); + SetKeyName("helmet"); + SetAdjectives( ({"iron", "thick", "viking", "horned", "formidable", + "protective"}) ); + SetId( ({"helm", "headgear", "cover"}) ); + SetShort("a horned viking helmet"); + SetLong("Vikings didn't really wear horned helmets into combat, but this + one does look formidable with its large bull horns and thick iron construction. + It should prove very protective."); + SetMass(200); + SetDamagePoints(100); + SetArmorType(A_HELMET); + SetProtection(BLADE, 20); + SetProtection(BLUNT, 15); + SetProtection(TRAUMA, 10); + + SetProtection(KNIFE, 25); + } + void init(){ + ::init(); + } + %^GREEN%^ l %^RESET%^ + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + A horned viking helmet and a heavy war hammer are here. + The Dude is standing here. + + + %^GREEN%^ exa dude %^RESET%^ + This is just some random guy. + The male human is in top condition. + Guy is carrying: + A heavy war hammer (wielded in left hand and right hand) + + %^GREEN%^ add helmet to dude %^RESET%^ + ob2: /realms/testycre/area/npc/guy.c + ob: /realms/testycre/area/armor/helmet.c + Please enter a command for the NPC to perform with this item. If you have no + such command to enter, enter the number of these items you want to add: + %^GREEN%^ wear helmet %^RESET%^ + Indenting file... + "/tmp/indent.1134437927.tmp.dat" 23 lines 544 bytes + Exit from ed. + + /realms/testycre/area/npc/guy: Ok + Guy wields a heavy war hammer. + Guy wears a horned viking helmet. + SetInventory modification complete. + %^GREEN%^ exa dude %^RESET%^ + This is just some random guy. + The male human is in top condition. + Guy is carrying: + A heavy war hammer (wielded in left hand and right hand) + A horned viking helmet (worn) + + //// Ok our dude is done. Let's clean up the room by updating it: + %^GREEN%^ update %^RESET%^ + Updating environment + /realms/testycre/area/room/test2: Ok + %^GREEN%^ l %^RESET%^ + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + %^GREEN%^ pwd %^RESET%^ + /realms/testycre: + %^GREEN%^ cd area/npc %^RESET%^ + /realms/testycre/area/npc: + //// We need to have the guy present in order to add him to the room: + %^GREEN%^ clone guy %^RESET%^ + Guy wields a heavy war hammer. + Guy wears a horned viking helmet. + You clone The Dude (/realms/testycre/area/npc/guy.c). + %^GREEN%^ add guy to room %^RESET%^ + ob2: /realms/testycre/area/room/test2.c + ob: /realms/testycre/area/npc/guy.c + Please enter the number of these that you want to add: + %^GREEN%^ 1 %^RESET%^ + Indenting file... + "/tmp/indent.1134437999.tmp.dat" 26 lines 485 bytes + Exit from ed. + + /realms/testycre/area/room/test2: Ok + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + The Dude is standing here. + + + SetInventory modification complete. + %^GREEN%^ update %^RESET%^ + Updating environment + /realms/testycre/area/room/test2: Ok + //// That's it. Easy, huh? Think of how much slogging through ed this would save you when making a large area. + %^GREEN%^ l %^RESET%^ + /realms/testycre/area/room/test2 + Room 2 [w] + This is the second test room. + The Dude is standing here. + + + %^GREEN%^ exa dude %^RESET%^ + This is just some random guy. + The male human is in top condition. + Guy is carrying: + A heavy war hammer (wielded in left hand and right hand) + A horned viking helmet (worn) + + %^GREEN%^ more here %^RESET%^ + #include <lib.h> + #include "/realms/testycre/customdefs.h" + + inherit LIB_ROOM; + + static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Room 2"); + SetLong("This is the second test room."); + SetExits(([ + "west" : "/realms/testycre/area/room/test1", + ])); + + SetItems( ([ + "template" : "That's what this is.", + ]) ); + + SetInventory(([ + "/realms/testycre/area/npc/guy" : 1, + ])); + } + + void init(){ + ::init(); + } + + %^GREEN%^ quit %^RESET%^ + Please come back another time! + + Obviously you still need to code some LPC in ed for complex stuff. But knocking out rooms and NPC's and objects quickly helps you avoid getting bogged down in mechanics when what you really want to do is build. + + diff -c -r --new-file ds1.1/lib/doc/help/creators/security ds2.1/lib/doc/help/creators/security *** ds1.1/lib/doc/help/creators/security Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/security Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,74 ---- + Nightmare 3.3/Foundation I Security + Created by Descartes of Borg + + Nightmare 3.3 has moved to a new style of security called stack + security. Stack security differs completely from the old EUID/UID + method. This document attempts to detail stack security. + + Stack security relies on checking an entire call stack for security + operations. With the old style security, the master object would only + check the to see if the object asking for access had access to perform + a certain operation. For example, say object A wanted to write to a + file. No matter how it got to desire to write to that file, the + master object would allow or deny it access based solely on its + merits. A good way, therefore, to defeat the old security system + would be to fake out object A and get it to write to a file using its + priveledges for you. + + With stack security, an object cannot be used to fake out the master + object. Instead, the master object traverse the entire call stack to + be certain that it should allow access. Take a rm command. + + I issue the command rm. The player object calls the command daemon. + The player object then calls the rm command. The rm command tries to + rm the file. So you have 3 objects here on the stack, my player + object two times, and the rm command (the command daemon made no + external calls, so it is not on the stack). In order for the rm + command to succeed, I and the rm command must all have access to rm + the file. As an admin, I have the access, and the rm command as well + has that access, so the command succeeds. If it had been a regular + creator however, perhaps trying to rm the master object, the operation + would have failed. The rm command still would have had access, but + the creator's player object would not have. + + In order to understand how this works, you must understand the + difference between file protection and object access. File protection + is the level of protection a file has from operations of other + objects. File protections are defined in /secure/cfg/read.cfg and + /secure/cfg/write.cfg. File protections must ALWAYS be greater than + or equal to the access an object cloned from that file has. If not, + then you have a security leak. + + File access is defined through the SimulEfun file_privs(). Upon + creation, each object gets a privs string which is a list of privs + separated by a :. Player objects always have their name as part of + their privs string. Privs can never change once set. + + By making protection greater than access, what I mean is this: + Any object which has access to a given file should on its own have + access to any files which an object created from that file would have + access to. For example, /secure has access to everything. Therefore, + only SECURE objects should have access to it. If you allow any priv, + say an admin priv like descartes, to have access to /secure, you are + by default giving SECURE access to that outside priv. So now anything + which can write to my home directory can become SECURE! + + The final key to the stack security system is the unguarded() + SimulEfun. + + mixed unguarded(function f); + + Any object can make an old-style, depend on me only operation by + making that function unguarded. For example, I am a creator that has + a guild object which needs to save to my home directory. My guild + object has write access to my home directory, but players using it + would not. So stack security would make it impossible for you to have + any such object. If, in the guild object, you have the following + call: + + unguarded((: save_object, "/realms/descartes/guild/save/obj" :)); + + The object will saved based SOLELY on the permissions which the guild + object has. If the guild object can write to the directory, then the + operation succeeds regardless of the rest of the stack. If the guild + object can't do it, then the operation fails. diff -c -r --new-file ds1.1/lib/doc/help/creators/staff ds2.1/lib/doc/help/creators/staff *** ds1.1/lib/doc/help/creators/staff Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/creators/staff Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,25 ---- + Dead Souls Magical Wooden Staff + + The Dead Souls Quick Creation System is a big, complicated mess + for a number of reasons, mostly having to do with the necessity of + interpreting potentially unusual code. + + Among the compromises made to get the system working is that it is + bound to a specific object that must be carried. The original plan + had called for a daemon, but the modular design and need for global + variables meant either a mind-numbingly complex workaround, or individuating + the daemon functions. + + Making the QCS work through a special object simplifies the + interaction between modules, and limits the memory overhead to the + few characters that have a need to use it. + + Thus, in order to use QCS, you must be carrying the creator's staff, + which is /secure/obj/staff.c + + It doesn't have to be a staff. If you prefer it to be a hat, or a + gold watch, or whatever, feel free to make it so. Just remember that + the creation object must inherit the modules that the staff inherits, and + it must answer to the id "tanstaafl". + + diff -c -r --new-file ds1.1/lib/doc/help/players/alias ds2.1/lib/doc/help/players/alias *** ds1.1/lib/doc/help/players/alias Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/alias Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,28 ---- + Syntax: alias <short version> <long version> + alias <short version> <long version> $* + + This command lets you substitute a short command for a long one. + For example, rather than type out "get all from corpse" you + can create this alias: + + %^GREEN%^alias gc get all from corpse%^RESET%^ + + And all you need do is type "gc" to get the same effect. + You can also use a wildcard, like this: + + %^GREEN%^alias gc get all from $* corpse%^RESET%^ + + So that typing: %^GREEN%^gc first%^RESET%^ + Expands out to: %^GREEN%^get all from first corpse%^RESET%^ + + The wildcard is also helpful for channel aliases: + + %^GREEN%^alias ige intergossipemote $*%^RESET%^ + + To see your aliases, type: %^GREEN%^alias%^RESET%^ + + To remove an alias, type alias plus the alias, like so: + + %^GREEN%^alias gc%^RESET%^ + + diff -c -r --new-file ds1.1/lib/doc/help/players/banking ds2.1/lib/doc/help/players/banking *** ds1.1/lib/doc/help/players/banking Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/banking Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,35 ---- + + + Dead Souls Bankers/Tellers + + As with most other non-player characters (NPCs), bank tellers respond + to certain requests players make using the "ask" and "request" + commands. Dead Souls bank tellers respond to at least the following + requests: + + request account from TELLER + request balance from TELLER + ask TELLER to deposit AMOUNT CURRENCY + ask TELLER to withdraw AMOUNT CURRENCY + ask TELLER to exchange AMOUNT CURRENCY for CURRENCY + + examples: + + ask teller to deposit 100 gold + ask teller to withdraw 10 platinum + ask teller to exchange 10 electrum for silver + + notes: + + - All banks require a minimum balance to open an account. + To use any of the bank's services, you must first open an + account with the bank (request account...). + + - Banks may have more than one location. You can bank at any + location once you have opened an account with the named bank. + + - Some banks charge for certain transactions. The charges vary + from bank to bank, but may be influenced by whether or not you + are a local resident in the town the bank resides in. + + diff -c -r --new-file ds1.1/lib/doc/help/players/channels ds2.1/lib/doc/help/players/channels *** ds1.1/lib/doc/help/players/channels Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/channels Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,55 ---- + Channels are an out-of-character (OOC) means for users + to communicate with each other. You may hear the terms + "channel" and "line" used interchangeably. + + There are two main types of channels: local and intermud. + The default Dead Souls distribution uses these channels as + local: + + cre - only creators hear this + gossip - general offtopic stuff + newbie - everyone can hear this unless they turn it off + thief - channel for the thief class + fighter - channel for the fighter class + error - system errors + death - death announcements + mage - channel for the thief class + priest - channel for the thief class + explorer - channel for the thief class + admin - only admins hear this + + The following are intermud channels: + + ds - Dead Souls mud code talk + ds_test - testing testing 1, 2, 3, etc + intergossip - general offtopic stuff + lpuni - LPUniversity discussion + intercre - general technical chatter + + + By default, players do not have access to intermud channels. + Mud admins are asked to maintain some level of adherence to + the channel topics from their users. Muds that violate the + router admin's interpretation of "on-topic" will be asked + politely, if possible, to conform to the channel standards. + + Continued violations subject the offending mud to potential + banning. + + Hate speech is not tolerated, and flaming is frowned + upon, though each mud is expected to police itself and + enforce these standards on their own. + + If you don't like these rules, use a router other than the default. + + For local channels of course, none of this applies. Whatever + local rules are in place, that's what must be obeyed. + + Some tips: + --------- + To turn on/off a channel, type its name by itself, like this: newbie + + To know who is listening to a channel: list newbie + + To see a brief history of channel messages: hist newbie + diff -c -r --new-file ds1.1/lib/doc/help/players/classes ds2.1/lib/doc/help/players/classes *** ds1.1/lib/doc/help/players/classes Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/classes Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,46 ---- + Dead Souls LPMud Character Classes + Originally written by Mikla and Xymox 95111 + Last Modified: 951111 + + As a character on Dead Souls, your learned abilities, also known as + skills, are determined by your class. Before you join a class, you + have no skills and are able to do virtually nothing. It is thus + essential that you join a class as soon as you have determined how you + wish to play Dead Souls. + + How do you wish to play Dead Souls? + Dead Souls can be played towards many different ends, limited only by + your imagination. Each class is designed to fit a different playing + philosophy and experience. For example, some people prefer pure + "hack-n-slash" gaming. Fighters are well suited to this type of + player. Other players, however, prefer socialization and role-playing + over monster killing and adventuring. Fishers are ideally suited + towards this end. + + When you join a class, you will be provided with set of skills both in + which your class excels over others as well as which determine your + success within your class. In addition, you gain an improved ability + for learning, both through training and experience, those skills that are + associated with your class. + + What you choose to do with these skills is up to you. Membership in a + class only suggests that you have certain talents that you tend to + specialize at or that you are simply just naturally good at. Once you + join a class, you are a member for life, and it becomes your primary + source of power. In the reality of Dead Souls, there are four basic + classes of people: + + clerics, fighters, mages, thieves. + + There are help files on each of these. + + Each class has four primary skills, as well as other skills which are + important to them. The primary skills determine your level. Level is + simply a way to measure how good you are at your class. It does not + serve as a method for comparing players of different classes. In + other words, the only thing you can say about a level 10 fighter and a + level 10 mage, is that the mage magicks as well as the fighter + fights. It does not suggest that the fighter should be able to cast spells + as well as the mage, nor that the mage should be able to fight as + well as the fighter. + diff -c -r --new-file ds1.1/lib/doc/help/players/communication ds2.1/lib/doc/help/players/communication *** ds1.1/lib/doc/help/players/communication Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/communication Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,105 ---- + + There are many ways to communicate with other players. If + you're in the same room as your intended listener, you can just + use the "say" command, like this: + + %^GREEN%^say hi, crat%^RESET%^ + + If the message is secret, you can "whisper": + + %^GREEN%^whisper to cratylus are you idle?%^RESET%^ + + If you want to say something that everyone in the mud can + hear, use the "shout" command (at the cost of a lot of stamina): + + %^GREEN%^shout hey crat, wheredya go?%^RESET%^ + + Or, if it's an important secret and the target is not in the + same room as you, you can use the magical "tell" command: + + %^GREEN%^tell cratylus are you mad at me or something?%^RESET%^ + + + There are also special communication lines on the mud that are + class or role-specific. For example, if you type: + + %^GREEN%^newbie does anyone know what's up with cratylus?%^RESET%^ + + All people who are tuned into the newbie line will get + your message. To see what lines are available to you, type: + + %^GREEN%^lines%^RESET%^ + + To see who is listening to the newbie channel: + + %^GREEN%^list newbie%^RESET%^ + + To see who is listening to some other channel on some other mud: + + %^GREEN%^list otherchannel@othermud%^RESET%^ + + + To enable or disable a line, just type the name of it with no message. + + To see a brief history of the past few messages on a line (in + this case, the newbie line), type: + + %^GREEN%^hist newbie%^RESET%^ + + + Spamming lines is rude and probably dangerous to your character, so + be sure you comply with your mud's rules on lines. + + + Your mud may be on the intermud network. To find out, type the + command: + + %^GREEN%^mudlist%^RESET%^ + + If a list of muds comes up, you know your mud is probably + on the intermud3 communication network. Dead Souls by default restricts + players from access to intermud channels, but you can "tell" to + players on other muds, if you want. If you think your friend Xyzzy + is online on a mud on intermud3, you can issue this command: + + %^GREEN%^locate xyzzy%^RESET%^ + + If he's logged into a mud on i3, you will get something like: + + Xyzzy was just located on Frontiers. (idle 00:03:17) [status: inactive] + + You can then tell to him: + + %^GREEN%^tell xyzzy@frontiers dude, what's the deal with crat lately?%^RESET%^ + + + Sometimes a player or NPC does not understand your character's + native tongue. For example, if you are en elf, your native tongue is + not English, it is Edhellen. If someone talks to you in English, you + might see something like this: + + Xyzzy says in English, "leka mifahmam, potong-hwa." + + Since your character doesn't speak English, what you see is gibberish. + If you find a language teacher, your proficiency in the language they + teach you will allow you to understand more of the words you hear. + + Suppose that your elf character is now 100% fluent in English. + If you greet a human player named Xyzzy by typing: + + %^GREEN%^say hello there, xyzzy%^RESET%^ + + Xyzzy will probably see something like: + + Noobie says in Edhellen, "pericolo temak, forshtor." + + Instead, if you want to speak to a human, you'll have to type: + + %^GREEN%^speak in english hello there, xyzzy%^RESET%^ + + + To find out what languages you speak, type: + + %^GREEN%^language%^RESET%^ + + diff -c -r --new-file ds1.1/lib/doc/help/players/credits ds2.1/lib/doc/help/players/credits *** ds1.1/lib/doc/help/players/credits Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/credits Tue Jul 11 18:36:11 2006 *************** *** 0 **** --- 1,37 ---- + I'd like to thank the following people for their help, witting or + otherwise, in making the new release of Dead Souls possible: + + Sine qua non: Descartes, the legion of MudOS developers, and + all those coders who toiled at Nightmare, and Lars Pensjö. + Marius for his kind permission to bundle MudOS. + + Direct conributors: Haderach and his clever code and inspiration, Duuk + and his willingness to let me poke through his lib and + filch code. Great thanks to Marajin for his direct and + substantial contribution to the Windows port. + Much gratitude to Saquivor, for whom a town street is + now named, for getting the Windows socket code working. + Thanks also to the following for code donation, + support, and/or contribution: Tim@TimMUD, Manchi, + Brodbane, Ashon, Shadyman, Jonez, Cecil, Daelas. + + Appreciation of: Jayren, Kaylus, Arianrhod, Nosmo, Pyro, Abby, Balmung, + Aten, Metiscus, Garfield, Javelin, Alensin, Daelas, Root, + Kristus, Zeus, Dastuun, Detah, and Nulvect for their + thoughtful comments and suggestions. + Thanks to Frostmud.com for letting me test on their box. + + Much gratitude to playtesters: Karri, Aten, Tacitus, Kaatil, Atomic. + + Also: Xyzzy He Is Cool + + The following people/organizations provided me with free products/services + they normally charge for that allowed me to complete this project: + - Wolfpaw http://wolfpaw.net/ + - Sun Microsystems http://www.sun.com + Note: This does not indicate an official corporate sponsorship of + any kind. It is simply charity that is well appreciated. + + Cratylus @ Dead Souls + July 2006 + diff -c -r --new-file ds1.1/lib/doc/help/players/handbook ds2.1/lib/doc/help/players/handbook *** ds1.1/lib/doc/help/players/handbook Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/handbook Wed Jul 12 13:29:17 2006 *************** *** 0 **** --- 1,838 ---- + chapter 1 "Introduction" + + If you are unfamiliar with LPC based muds in general or Dead Souls + mudlib in particular, you will find this handbook valuable in + orienting you around what you can do and how you can do it. + + Keep in mind that this handbook describes the features of a mud + running an unmodifed version of the lib. The mud you are on may + differ somewhat, though probably not extremely so. + + To advance a page in a chapter, just hit "return". + + Let's start with just navigating this book. Once you are done + reading this chapter, you can read the next chapter by typing: + + %^GREEN%^read chapter 2 in handbook%^RESET%^ + + Make sure you wait until you are done reading this chapter, + though. The reason you should wait is that you are now in "reading + mode", which means that anything you type and send to the mud + is actually a command to the editing system that is displaying this + text. + + To leave reading mode (or more accurately, pager, or ed mode) + you can hit "return" a bunch of times to complete the chapter, thus + automatically exiting the pager. Another way is to enter the + letter "q" (without the quotes) and then "return". That will also + make you stop reading. + + When you are not in reading mode, you can find out the chapter + titles by typing: + + %^GREEN%^read index in handbook%^RESET%^ + + You really should read the whole thing, but in case you don't, the + chapter titles will help as a reference to find the information you + need. + + Something to watch out for is that if you or your environment + contain another handbook, the mud may not know which one you are + trying to read. If you get a message like "Which of the two handbooks + would you like to read?", you can try one or more of the following: + + %^GREEN%^read index in first handbook%^RESET%^ + + %^GREEN%^read index in my handbook%^RESET%^ + + %^GREEN%^read index in my first player handbook%^RESET%^ + + + \n + chapter 2 "Command Syntax: Doing Stuff" + + + Section 1: Manipulating Objects + ---------- + + You've already noticed that Dead Souls, like most modern LP muds, + uses natural-like command syntax, like: + + %^GREEN%^read first handbook%^RESET%^ + + rather than: + + %^GREEN%^read handbook 1%^RESET%^ + + This is because Dead Souls uses a natural language parser. It isn't + perfect, of course. If you try to "put all apples from box in my bag after + opening them" you won't see much success, but this will work: + + %^GREEN%^open box%^RESET%^ + + %^GREEN%^open bag%^RESET%^ + + %^GREEN%^get apples from box%^RESET%^ + + %^GREEN%^put apples in bag%^RESET%^ + + The parser will understand "the first box" or "my second bag", + assuming those objects exist in your inventory or in your environment. + + If you want to know what is in the box, the command is: + + %^GREEN%^look in box%^RESET%^ + + The command "look at box" or "examine box" will usually *not* show + you the contents of that box. This is because normally, boxes are + opaque, and in the real world, just looking at a box is rarely enough + to see what it contains as well. + An exception to this rule are transparent containers (a glass + trophy case, perhaps) whose interior is always visible from the + outside. + + Sometimes looking at an object reveals its contents because of + the nature of the object. A table, for example, can have things on it, + and typing: + + %^GREEN%^look at table %^RESET%^ + + ...will usually let you know what is on it. It is also possible to + see what other players are carrying by just looking at them, + unless what they have is inside a container. + You'll want to remember that while you can "put apple in bag", + if you want to put that apple on a surface like a table, you'll + need to: + + %^GREEN%^put apple on table%^RESET%^ + + You can give things to people, and they will automatically + accept them. However, you may not "take" or "get" things from living + beings. It's theirs, and it's up to them if they want to share. + You can try to "steal sword from fighter" if you dare, but unless + you have trained a lot, this is unlikely to succeed. We'll talk + more about training and skills in a later chapter. + Naturally you may also drop things you no longer need, though + it's nicer to your fellow mudders (and the mud's memory) to put + them in recycling bins so the bits can be reused. + Some other common object manipulation commands are: + + close, donate, attack, eat, drink, listen, smell, search, + shoot, touch, turn. + + There are many others you may find useful, but these will be + the ones you use most often to handle simple objects. + + * A note about articles: + + Dead Souls understands both definite and indefinite articles. + This means that you can refer to a specific apple, like so: + + %^GREEN%^get the apple%^RESET%^ + + But you can also be unspecific. If there are a dozen + apples in a crate and you don't care which one you pick up: + + %^GREEN%^get an apple from the crate%^RESET%^ + + + Section 2: Navigation + --------- + + Moving around here is probably much like any other mud. You + can expect to move mostly in cardinal directions (like north and + northwest), but you may sometimes need to go up, down, or out. + Strictly speaking, the way to do this is: + + %^GREEN%^go south%^RESET%^ + + %^GREEN%^go out%^RESET%^ + + ...and so on, but this can get tedious after a while. Instead + of having to type in "go" plus the entire direction, the mud allows + you to enter shortcuts like "sw" for "go southwest" or "u" for + "go up". + + When you enter a room, very often you will see letters in + brackets above the room description, like this: [n, u, out] + These are the "obvious exits" of that room, and help you + quickly find your way around without having to go through each + description. But remember! Just because a room has obvious exits + doesn't mean those are the only exits. Sometimes a room must + be searched to discover an exit, or there may be an exit available + that just doesn't happen to be very obvious. + If a room is dark, obvious exits may not be visible at all. + + Aside from those ordinary means of travel, there are situations + that require more specific locomotion than just "go". These are + examples of the use of some other commands to get around: + + %^GREEN%^jump onto road%^RESET%^ + + %^GREEN%^enter window%^RESET%^ + + %^GREEN%^climb ladder%^RESET%^ + + %^GREEN%^crawl east%^RESET%^ (if you are lying down and can't get up) + + %^GREEN%^fly up%^RESET%^ + + %^GREEN%^follow thief%^RESET%^ + + %^GREEN%^evade hunter%^RESET%^ + + + Section 3: Armor + ------- + + Now that you can manipulate objects and move around, you'll want + to be able to defend yourself, should the need arise. The special + object categories of "weapons" and "armor" should help. + + Armor is an item that can be worn. That means that a pair of + blue jeans is considered armor, and a suit of chainmail is considered + armor as well. Basically, if you can wear it, it's "armor", because + whether it's a lot or a little, it protects you. + Assuming you are humanoid, you have the following limbs: + + head, neck, torso, right arm, right hand, left arm, + left hand, right leg, right foot, left leg, left foot. + + Properly coded armor must be worn on the corect limbs. Usually + a command like: + + %^GREEN%^wear chainmail%^RESET%^ + + or + + %^GREEN%^wear all%^RESET%^ + + ...will cause you to automatically wear armor where it makes + most sense. However, it is possible to find armor that, + for example, can be worn either on your neck or your torso, like + an amulet. If this is so, you'll need to specify where you want it. + There are various types of armor, like cloak, pants, glove, + etc. Many of them overlap. You can wear a shirt on your torso as + well as a cloak and combat armor, but you may not wear two of + the same type. If you have a robe and a cape that are both cloaks, + you'll have to decide which one is going on. + You will find that shoes and gloves are often for one of your + hands but not the other. Sometimes you will find shoes, or gloves + that don't care which appendage they occupy, but usually these + are simply incorrectly coded. + + If you are of some exotic or non-humanoid race, you may have + additional limbs to consider, and humanoid armor may not work for you. + + + Section 4: Weapons + --------- + + You may be surprised to learn that almost any manipulable object + can be wielded as a weapon, or thrown as a missile. You can wield + a can of Spam and try to kill an orc with it...and you may even succeed, + if you are strong and tough enough. Don't count on it, though, + and instead go for items that are made specifically with personal + security in mind. + + There are four main types of weapons: + + knife: knives, daggers + blade: like swords, and spears + blunt: like clubs, staves, and shillelaghs + projectile: things designed to be thrown, like darts or grenades + + Unless it is a special device or magical item, weapons + must be wielded in order to be of use in combat. Some weapons, + like staves or pikes, may require the use of both hands. If this + is the case, wearing a shield may not be possible at the same time. + Like armor, weapons differ in quality and effectiveness. A + "well-crafted sword" is probably a better choice than a "small + rusty knife", but then again, you never know. Maybe rusty knives + are exactly what some monster is most vulnerable to. + + Note also that, like armor, weapons wear down with use. + Examples of commands that involve weapons or fighting: + + %^GREEN%^wield sword%^RESET%^ + + %^GREEN%^wield hammer in left hand%^RESET%^ + + %^GREEN%^wield staff in left hand and right hand%^RESET%^ + + %^GREEN%^unwield dagger%^RESET%^ + + %^GREEN%^shoot gun at otik%^RESET%^ + + %^GREEN%^throw dart at beggar%^RESET%^ + + %^GREEN%^kill all%^RESET%^ (this makes an enemy of everyone in the room) + + %^GREEN%^ignore first orc%^RESET%^ (lets you concentrate on the other orcs) + + %^GREEN%^ignore all%^RESET%^ (don't fight anyone in the room, even if they are attacking you) + + %^GREEN%^target boss orc%^RESET%^ (this makes you ignore attacks from anyone else) + + %^GREEN%^wimpy 30%^RESET%^ (this makes you run away if your health points drop below 30%) + + + Section 5: Miscellaneous Things to to with Things + --------- + + %^GREEN%^turn on flashlight%^RESET%^ + + %^GREEN%^turn off flashlight%^RESET%^ + + %^GREEN%^strike match%^RESET%^ + + %^GREEN%^light torch with match%^RESET%^ + + %^GREEN%^extinguish match%^RESET%^ + + %^GREEN%^dig hole with shovel%^RESET%^ + + %^GREEN%^move bed%^RESET%^ + + %^GREEN%^search %^RESET%^ (by default searches the room) + + %^GREEN%^search rocks%^RESET%^ + + %^GREEN%^unlock east door with silver key%^RESET%^ + + %^GREEN%^bait pole with worm%^RESET%^ + + %^GREEN%^fish with pole%^RESET%^ + + %^GREEN%^stop fishing%^RESET%^ + + %^GREEN%^drop all%^RESET%^ + + %^GREEN%^donate 2 silver%^RESET%^ + + %^GREEN%^get all%^RESET%^ + + %^GREEN%^get all from corpse%^RESET%^ + + %^GREEN%^sell first right glove to otik%^RESET%^ + + %^GREEN%^sell all to otik%^RESET%^ + + %^GREEN%^buy sword from otik%^RESET%^ + + %^GREEN%^buy 8 from otik%^RESET%^ (get Otik to sell you item number 8) + + chapter 3 "Your Health and Abilities" + + In the previous chapter you learned the basics of getting + around and taking care of yourself. It's important also to care + *for* yourself, and this chapter describes the various aspects of + your body's state and what abilities you may have. + + + The command that tells you almost everything you need to + know is "stat". This diplays a whole lot of stuff, perhaps some of + it completely unfamiliar. Let's start at the top, using my output + as an example. + + First line: + ---------- + %^CYAN%^Cratylus aka Cratylus the unaccomplished, level 10 male human Explorer%^RESET%^ + + Here you see my short name, my name with title, my level, my + gender, my race, and my class. Let's go over each. + + * short name: What a person would use to address you. "look at cratylus", + for example. + + * name with title: This displays my title. Creators can have whatever title + they want. Players can only have the titles they earn. As a player, a + title is usually earned when you are promoted a level or complete a + quest, though it is not always so on every mud. + + * level: This is a measure of your overall experience, expertise, and + all-around game status. Being promoted a level means your skills, + health, and vital statistics increase. This often means you can handle + tougher monsters, for example, or tackle more challenging quests, learn + new spells, and so on. + + * gender: This has no effect on your status. It is a cosmetic feature + of your body that is only useful to you in the social context of your + fellow mud players. + + * race: In Dead Souls, race has nothing to do with your local genetic + makeup on planet Earth. In the mud, "race" refers to what one typically + would call "species" in real-life. An example of a race other than human + might be "orc" or "feline". Not all races are available for players. Once + you have chosen a race to play, it is in theory possible to change it, but + there is a nonzero chance you'll hose up your player file and lose your + character forever. Besides, it's up to your local admins whether race + changing is permitted on your mud. Different races have different + abilities. Elves see better in darkness, for example. Orcs are stronger + than some other humanoids, but dumber, too (which does affect gameplay). + + * class: This can be considered an occupational specialty. In the real + world you have plumbers, doctors, soldiers, etc. In the mud world, + we can have explorers, fighters, mages, and the like. Each class brings + its own unique advantages and disadvantages to your gameplay. A fighter + can really kick more butt in melee combat than a mage, but a mage + gets to cast powerful spells. Explorers are a middle of the road class + that gives you a bit of everything without specializing in anything. + + + + Next line: + ---------- + + %^CYAN%^Alive / Awake%^RESET%^ + + It is indeed possible for your virtual body to cease life functions. + When this happens your spirit speeds off to the land of the dead, + where you drift until you decide to "regenerate" and regain your + physical form. Except for some special magical items, anything you + were carrying when you died is with that dead body, so it's a good + idea to rush your new body back to the scene of the fatality and get + your stuff back before someone else grabs it. Death is not only + inconvenient, it also incurs major penalties on your statistics, so it + should be avoided. + It is also possible to sleep. If you are drunk and asleep, your + injuries will heal more quickly. It's magic, don't worry about the + logic behind it. + If you are attacked while sleeping, you will wake up. You can + force yourself awake, too, but it's a bit tedious. + + + Next line: + --------- + + %^CYAN%^Health: 350/350 Magic: 560/560 Stamina: 400/400 Carry: 1184/1300%^RESET%^ + + In each case, the number on the left of the slash indicates the + current level, and the number on the right indicates what the maximum is. + + health: When I am 100% healthy, I have a total of 350 hp. If my hp ever + reach 0 or less (!), I die. Poison and illness can cause hp's to + gradually decrease, and although with time my hp's will normally + return to 350 as I heal, poison and illness can slow down that healing + or even cause me to die. Injury in combat is the most common source + of hp loss, though spells, falls, and other adverse events can cause + you injury or death. + + magic: I cast magic missile! Spell casting takes a toll on your magical + abilities, and mp measure how much magic you've got left in you at + any given point. Like hp, mp gradually grow back to your max if you + avoid spellcasting for a while. + + stamina: Fighting is tough work, and swinging around swords while + getting bashed with hammers really takes a lot out of a guy. Therefore + keep an eye on this stat while you're fighting, because if it gets too + low you will collapse and be unable to do anything for a while. + + carry: Objects have mass, and your body is of limited size and strength. + My carry capacity is 0 when I carry nothing, and 1300 when I can + carry no more. Creators are allowed to exceed their bodies' carry + capacity, but players cannot. + + + Next line: + --------- + + %^CYAN%^Food: 0 Drink: 0 Alcohol: 0 Caffeine: 0 Poison: 0 %^RESET%^ + + These are pretty self-explanatory. Alcohol is good for healing, + bad for fighting. Food and drink also help speed healing. Poison + has the opposite effect. Caffeine can speed up your combat slightly, + but tends to prevent full rest. + You will not die from lack of food or lack of drink, but you + will do better with a body not starved for nutrients. + Your maximum load for any of these is not fixed, and varies + depending on many factors, such as level, endurance, etc. + + + Next line: + --------- + + %^CYAN%^Training Points: 0 Quest Points: 0 Experience Points: 50 %^RESET%^ + + Training points can be cashed in with special NPC's called + trainers, who can help you improve some skills. A trainer that + specializes in fighting might be able to raise your "blade attack" + skill, for example. you earn training points when you are + promoted a level. + + Quest points are awarded when you complete a quest. In + the default version of Dead Souls, you cannot advance past a + certain player level unless you earn some qp's. Read the sign + in the adventurers guild for more details on this. + + Experience points can be awarded for various reasons: completing + a quest, solving a puzzle, winning a contest. Most often you + will receive xp after killing an NPC. The amount of xp awarded + will depend on the level of the NPC. Like qp, xp are needed to + qualify for level advancement. + + + + Limb section: + ------------ + + Remember how wearing armor requires the right body parts? + Well here they are, and this is their health. You can issue the + "body" command for a quicker self-check. + Let's look at what the numbers mean with an example: + + %^CYAN%^left leg (2) 160/160%^RESET%^ + + Obviously the first item identifies the limb in question. + + The (2) is a kind of "importance score", indicating how critical + a body part is. If this number is (1), like the head, it means that + losing that limb causes immediate death. + + The number on the right side of the slash indicates the hit point + damage you may receive on that limb before it is severed. The number + on the left is how many of those hits you have left. + It doesn't mean my leg has 160 of my hitpoints. If that were true, + my hit points would add up to a heck of a lot more than 350. + This means that if I've lost, say, 200hp fighting a troll, and + 159hp of those hits were on my left leg, getting hit there again means I + lose my left leg. + I would then collapse and have to crawl away to seek medical attention. + Wearing armor on your limbs is a great way to minimize the danger of + this happening. + + + Skills section: + -------------- + + Let's review skills by examining one of mine: + + %^CYAN%^blade attack (1) 00% - 20/24%^RESET%^ + + This measures how likely I am to hit an opponent when I + use a blade, and how good a hit it was. The number (1) means + that this is a skill critical to my class. If an explorer can't + swing a sword, he oughta think about another line + of work. + The 00% means I have thus far earned no blade attack + experience toward achieving the next level of this skill. + The 20 is my current proficiency level. + The 24 is the maximum level I can reach at my current + player level and with my current stats. + + What's all this mean? Well, if I practice a lot of blade + attacking, that 00% will gradually climb up to 99, and one more + point causes me to go from a level 20 slicer of things to a + level 21 slicer of things. This increases my likelihood of + hitting my target in the future. + + Meaning, in short, practice a skill, and you'll get + better at it. + + Of course, if my blade attack level reaches 24, I can advance + my blade attack skills no further until my player level rises. + + + Stats section: + ------------- + + Remember these from Dungeons & Dragons? No? Well these vital + statistics measure your general giftedness in that feature of your + body. Let's look at one of mine: + + %^CYAN%^coordination (2) 42/42%^RESET%^ + + Coordination is one of those important stats for fighting and + such. The more coordinated you are, the more likely you are to hit your + target. The (2) indicates that this stat is important to my class, + but not critical. This influences its effect on my skills. + 42/42 means that my coordination is not currently impaired. If + someone cast a "stumble" spell on me, for example, this might look more + like 30/42, and if I were drunk, it would look very shabby indeed. + + Last section: + ------------ + + "Cratylus has amassed a net worth of 11 gold." means that when you + add up the money in my bank accounts and the money I'm carrying, + converted to gold, I have 11 gold to my name. It looks bad, but gold + is actually quite valuable in the default Dead Souls economy. + + "Money on hand: 79 dollars, 34 silver" means that this is the amount of + money I'm carrying. Don't forget that the amount of money you are carrying + affects your overall carry capacity. Gold is an especially heavy + currency. + + + Final notes: + ----------- + + "stat" is a great command to get thorough information about + yourself. It is, however, quite a screenful. Briefer reports can be + viewed with the following commands: + + %^GREEN%^body%^RESET%^ + %^GREEN%^skills%^RESET%^ + %^GREEN%^stats%^RESET%^ + %^GREEN%^score%^RESET%^ + %^GREEN%^status%^RESET%^ + + chapter 4 "Quests" + + Some muds don't have quests, and the fun people have is + through role-playing and social activities with other players. + + Other muds prefer to concentrate on killing lots and lots + of monsters, a lot, over and over. + + Quests give you a chance to problems-solve by performing some + series of actions that satisfies a pre-determined requirement. + + For example, Dead Souls' sample town contains a quest called + Orcslayer. Leo the archwizard lives in the basement of the old + abandoned church, and he has lost a powerful magic sword called + "Orcslayer". If you return it to him, he will reward you with + experience points, quest points, and a new title you can use. To + complete the quest, you need to defeat the warrior orcs, penetrate + deep into their lair, defeat the orc shaman, and take Orcslayer from + his corpse, then go to the church basement and give the sword to Leo. + + In this case, if you're a level 1 newbie, the orcs will massacre you + before you get anywhere near the shaman. So either team up with + friends to tackle the orcs together, or raise your level to the + point where you're tough enough to take them on. + + To raise your level, wander around in the newbie mansion, which + is south of the village church. + + There's lots of loot there you can sell at Otik's shop, and with the + cash you can then get some proper weaponry and armor. + + Silver is heavy, so don't try to carry all your money around + all the time. Request an account from Zoe the banker and keep your + money there until you really need it. + + There is a quest in the newbie mansion, and solving it by + finding the secret room will give you experience and quest points too. + (hint, there might be more than one secret room) + + Once you have enough experience and/or points, go to + Dirk in the adventurers hall and "%^GREEN%^ask dirk to advance%^RESET%^". + + Make sure you learn some spells from Herkimer, because if you + go up against a bunch of orcs in their lair, you'll want spells to + shield you from attacks, and spells to recover your strength after + combat. As a non-mage, your spell abilities will be limited at + lower levels, but as you gain levels you'll get better. Also, spells + will rarely work after you first learn them. Keep casting them, + even if you screw them up, so that your magic skills increase. + + Also, save your money. Drinking and sleeping help you heal, + but not fast enough. By the time those natural processes finish + and you're ready for combat again, the orcs may have gotten reinforcements. + So if you can afford it, buy healing slips and use them at Clepius' + healer's guild. His treatment is expensive, but you will heal much + more quickly. + + In the tragic event of the loss of a limb, Clepius can also magically + regenerate a new limb...but obviously at some great cost. + + There. I've just spoiled the Orcslayer quest for you. Normally, + all you'd know about a quest is a cryptic clue, like the one in the + scroll in the adventurers guild. Instead I've just spoiled the quest + for you by telling you all about it. They're more fun when you have to + figure them out on your own, like puzzles. + + Normally, spoiling quests like this is a bannable offense on + a mud, so if you solve a quest, keep it to yourself unless you know + the admins on your mud don't mind. + chapter 5 "Communication" + + There are many ways to communicate with other players. If + you're in the same room as your intended listener, you can just + use the "say" command, like this: + + %^GREEN%^say hi, crat%^RESET%^ + + If the message is secret, you can "whisper": + + %^GREEN%^whisper to cratylus are you idle?%^RESET%^ + + If you want to say something that everyone in the mud can + hear, use the "shout" command (at the cost of a lot of stamina): + + %^GREEN%^shout hey crat, wheredya go?%^RESET%^ + + Or, if it's an important secret and the target is not in the + same room as you, you can use the magical "tell" command: + + %^GREEN%^tell cratylus are you mad at me or something?%^RESET%^ + + + There are also special communication lines on the mud that are + class or role-specific. For example, if you type: + + %^GREEN%^newbie does anyone know what's up with cratylus?%^RESET%^ + + All people who are tuned into the newbie line will get + your message. To see what lines are available to you, type: + + %^GREEN%^lines%^RESET%^ + + To see who is listening to the newbie channel: + + %^GREEN%^list newbie%^RESET%^ + + To see who is listening to some other channel on some other mud: + + %^GREEN%^list otherchannel@othermud%^RESET%^ + + + To enable or disable a line, just type the name of it with no message. + + To see a brief history of the past few messages on a line (in + this case, the newbie line), type: + + %^GREEN%^hist newbie%^RESET%^ + + + Spamming lines is rude and probably dangerous to your character, so + be sure you comply with your mud's rules on lines. + + + Your mud may be on the intermud network. To find out, type the + command: + + %^GREEN%^mudlist%^RESET%^ + + If a list of muds comes up, you know your mud is probably + on the intermud3 communication network. Dead Souls by default restricts + players from access to intermud channels, but you can "tell" to + players on other muds, if you want. If you think your friend Xyzzy + is online on a mud on intermud3, you can issue this command: + + %^GREEN%^locate xyzzy%^RESET%^ + + If he's logged into a mud on i3, you will get something like: + + Xyzzy was just located on Frontiers. (idle 00:03:17) [status: inactive] + + You can then tell to him: + + %^GREEN%^tell xyzzy@frontiers dude, what's the deal with crat lately?%^RESET%^ + + + Sometimes a player or NPC does not understand your character's + native tongue. For example, if you are en elf, your native tongue is + not English, it is Edhellen. If someone talks to you in English, you + might see something like this: + + Xyzzy says in English, "leka mifahmam, potong-hwa." + + Since your character doesn't speak English, what you see is gibberish. + If you find a language teacher, your proficiency in the language they + teach you will allow you to understand more of the words you hear. + + Suppose that your elf character is now 100% fluent in English. + If you greet a human player named Xyzzy by typing: + + %^GREEN%^say hello there, xyzzy%^RESET%^ + + Xyzzy will probably see something like: + + Noobie says in Edhellen, "pericolo temak, forshtor." + + Instead, if you want to speak to a human, you'll have to type: + + %^GREEN%^speak in english hello there, xyzzy%^RESET%^ + + + To find out what languages you speak, type: + + %^GREEN%^language%^RESET%^ + + + chapter 6 "Note to New Creators" + + You should probably hang on to this book for reference. If + you lose it, pick up a copy at the adventurers hall. + + However, you need to start reading the Creators Manual. If + you don't have one on you, get the one in the chest in your workroom. + + If you're new to coding, start with chapter 31. It'll + get you started with the Quick Creation System, or QCS. + + Cratylus @ Frontiers + 04 Jan 2006 + chapter 7 "Hints and tips" + + * The "wimpy" command helps you avoid death due to inattention or + network lag. If you "wimpy 20", you will automatically try to escape + combat if your health goes below 20% of your maximum. + + * "target" and "ignore" are extremely useful when fighting more than + one enemy. You should always target the toughest npc first, and + always ignore any npc who can't get up because their foot or leg + is severed. + But if they collapse due to exhaustion, it's a good idea to keep + beating on them, otherwise they may get back up and get healthy sooner + than you expect. + + * By default, different races speak different languages. If someone + says something to you and you see no words in the same language as + the rest of the mud, it means they are speaking a language you do + not understand. + For example, if you are an elf, and you ask Radagast to teach + magic attack, you might get something like this: + + Radagast exclaims in English, "embleer con boltehe oota goota nehi auch" + + Even though in the real world you may speak English fluently, in + the mud world, you do not speak English fluently. As an elf, your + native tongue is Edhellen, and you may find human speech incomprehensible. + + If you find a trainer to teach you English, your skills in that + language will need time to improve. As you get better at a language, + you will see fewer gibberish words. + + If you are a "newbie", this does not apply to you. A newbie in the + default Dead Souls distribution is a player at level 4 or below. This + definition may be changed by your admin. + Newbies need all the help they can get just to survive, so they + are magically granted understanding of all languages, until they outgrow + their naivete. + + If you are a student of languages in the Real World, you may + recognize many of the "gibberish" words used by Dead Souls to represent + a foreign tongue. Your understanding of these words is not useful in + the context of the game, however, because they are not intended to + convey meaning other than "non-comprehensible words". + + + * Your ability to see is affected by various things: + + - A room's ambient light level + - Time of day + - Local light sources (flashlights, torches, etc) + - Your race's light sensitivity + - Magical effects + - Exposure to an excessive-light event + + It's important to remember that a room may be too dark for + you to see everything in it. You might be able to see the description + of a room with no problem, but it may be necessary for you to + light a torch in order to see the treasure chest there. + + In the same way that darkness can impair vision, brightness + can do the same. For elves, an outdoor area in bright sunlight that + contains additional light sources can be just as hostile to + vision as a dark cave with no torch would be for a human. + Regardless of race, a sufficiently adverse event, such as + a bright flash or special spell, can render you temporarily blind. + + As with languages, newbies have some exemption to light-level + limitations. + + * Mages can wield knives but are pretty much helpless with any other + vind of edged weapon. diff -c -r --new-file ds1.1/lib/doc/help/players/languages ds2.1/lib/doc/help/players/languages *** ds1.1/lib/doc/help/players/languages Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/languages Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,39 ---- + Dead Souls Languages + + Languages are essential to the way interaction occurs among players + and non-player characters. Every discussion you will have with an npc + will be done through that npc's native tongue generally (although some + npc's are more aware of other languages). + + When starting as a newbie, you will not much notice this. Newbies are + given full knowledge of all languages. This, however, does not last. + Once you cease to be a newbie, you only know your native language, + which you learn based on your race. + + As time goes on, you may wish to learn new languages. Certain npc's + across Dead Souls specialize in teaching people other languages. In + order to learn a new language, use the "ask" command to ask the npc to + teach you the language. The syntax is <ask LIVING to teach me LANGUAGE>. + For example: + + %^GREEN%^ask the sage to teach me nymal%^RESET%^ + + Not all teachers may know all languages. The teacher must naturally + know the language in order to teach it. + + The teacher will generally start spouting phrases in the language, + asking you to repeat them. It is to your advantage to try and repeat + what the teacher is saying in the language it is being said. + + To know what languages you speak, type: language + + To speak in a language other than your native one, type: + + speak in LANGUAGE MESSAGE + + example: + + %^GREEN%^speak in edhellen hi i speak a little elvish%^RESET%^ + + + See also: ask, shout, speak diff -c -r --new-file ds1.1/lib/doc/help/players/password ds2.1/lib/doc/help/players/password *** ds1.1/lib/doc/help/players/password Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/password Tue Jul 11 18:36:11 2006 *************** *** 0 **** --- 1,5 ---- + Users can change their own passwords with the command: passwd + + Admins can change someone else's password with: resetpasswd + + diff -c -r --new-file ds1.1/lib/doc/help/players/player_general ds2.1/lib/doc/help/players/player_general *** ds1.1/lib/doc/help/players/player_general Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/player_general Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,23 ---- + Basic player commands: + + look - get a view of your environment + inventory - take stock of your possessions + stat - your health and statistics + score - your overall ranking and information + + Dealing with objects: + -------------------- + look at, look in + get, drop, put, give + open, close + read + wield, unwield, wear, remove + + Moving around: + ------------- + n, s, e, w, ne, nw, se, sw, u, d + enter, go out, climb up, climb down, jump down + crawl, fly + + See also: help help + diff -c -r --new-file ds1.1/lib/doc/help/players/points ds2.1/lib/doc/help/players/points *** ds1.1/lib/doc/help/players/points Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/points Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,47 ---- + * Dead Souls Training Points * + Written by Blitz@Dead Souls 960904 + + What are training points? + + Training Points are awarded for achieving a new level. They + are not meant to be a means of advancing in the game, training + points are to be considered an extra bonus. + + How can I see my points? + + Your training points are listed under the "score" command. + + How are points earned? + + As stated above, Training points are earned when you gain + a new and "unique" level. A unique level is defined as a + a level you have never before attained with your character. + + How does death affect points? + + If you happen to lose a level (or levels) upon dying you + will be penalized 4 points per level. This does not apply + to newbies simply because they do not lose levels from + dying. + + For example, player Bob raises to level 6 and earns four + training points. Player Bob dies a horrible death and + finds himself at level 5 once again. Because Bob lost + a level he received -4 points. When our example reaches + level 6 again, he will "technically" earn 4 points to + compensate for the recently lost points. As you can see, + a player can only truly earn points for each "unique" + level gained. + + How do I use my training points? + + Throughout Dead Souls there are a number of NPCs who specialize + in training various skills. Trainers accept the following + commands; "ask <NPC> to help" will list the skills that the + NPC is capable of training. "ask <NPC> to train <SKILL>" + will start the process of training in the named skill. + + Please note that creators (including arches) cannot answer + questions regarding non-technical game play. To find a + trainer, you must search for yourself or ask other players. + diff -c -r --new-file ds1.1/lib/doc/help/players/races ds2.1/lib/doc/help/players/races *** ds1.1/lib/doc/help/players/races Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/races Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,36 ---- + Your race determines your genetic make-up. + + Some races are genetically predisposed to being stronger, sturdier, + more intelligent, more sensitive to light, etc. than other races. + In addition, different races are physically different from others, + having different limbs and other types of body parts. + In real life, you had no choice. You were born human. In the Dead Souls + reality, you do get a choice. Your choice should be based on your + style of playing? Do you want a magical character? Or do you + want to play the game by brute force? Or perhaps deception or + skullduggery? + + What do you prefer to explore? Do you like dark, enclosed areas? Or do + you like well lit castles or the open outdoors? + + Do you wish to have humanoid limbs which can be easily equipped? Or + are you interested in the advantages of having different limbs which + might allow you to wield more than two weapons at a time but are not + so easily equipped? + + All these questions face you now. Whatever choice you make, so long + as it fits the style in which you like to play, will be rewarding. + There is neither a best pick nor a worst pick. There is only what is + best or worst for your style. + + Towards that end, here are some clues: + Intelligence and wisdom make the best magic users. + Strength and constitution make the best fighters. + Dexterity and charisma make the best roguish types. + + Each race has its own help file. For example, to find out about humans, + type "help human". + + Type 'list' to see the selection while in the setter room. + + Type 'pick RACE' (for example, pick human ) to choose a race. diff -c -r --new-file ds1.1/lib/doc/help/players/vendors ds2.1/lib/doc/help/players/vendors *** ds1.1/lib/doc/help/players/vendors Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/help/players/vendors Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,35 ---- + Dead Souls Vendors + + As with other non-player characters, vendors respond to certain + requests people make using the "ask" command. Dead Souls vendors + respond to at least the following requests: + + %^GREEN%^ask VENDOR to appraise ITEM %^RESET%^ + %^GREEN%^ask VENDOR to browse%^RESET%^ + %^GREEN%^ask VENDOR to buy ITEM %^RESET%^ (identical to sell ITEM to VENDOR) + %^GREEN%^ask VENDOR to price ITEM%^RESET%^ + %^GREEN%^ask VENDOR to sell ITEM %^RESET%^ (identical to buy ITEM from VENDOR) + %^GREEN%^ask VENDOR to show ITEM%^RESET%^ + + Appraise allows you to get an offer from the vendor for an item you + might wish to sell. + + Browse allows you to browse through what the vendor has to sell. You + may also specify specific types of things to browse, for example: + %^GREEN%^ask VENDOR to browse helms%^RESET%^ + %^GREEN%^ask vendor to browse torches%^RESET%^ + + Buy requests that the vendor buy from you the item you specify. This is + identical to the sell command, so see "help sell". + + Price allows you to get the price of an item that the vendor has to + sell. + + Sell requests that the vendor sell you the specified item. This is + identical to the "buy" command, so see "help buy". + + Show allows you to look at an item which the vendor has for sale. + + See also: ask, buy, sell + + diff -c -r --new-file ds1.1/lib/doc/lpc/basic/Contents ds2.1/lib/doc/lpc/basic/Contents *** ds1.1/lib/doc/lpc/basic/Contents Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/Contents Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,13 ---- + LPC Basics + Written by Descartes of Borg + 23 april 1993 + + Introduction + Chapter 1: Introduction to the Coding Environment + Chapter 2: The LPC Program + Chapter 3: LPC Data Types + Chapter 4: Functions + Chapter 5: The Basics of Inheritance + Chapter 6: Variable Handling + Chapter 7: Flow Control + Chapter 8: The Data Type Object diff -c -r --new-file ds1.1/lib/doc/lpc/basic/Introduction ds2.1/lib/doc/lpc/basic/Introduction *** ds1.1/lib/doc/lpc/basic/Introduction Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/Introduction Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,104 ---- + LPC Basics + Written by Descartes of Borg + 23 april 1993 + + + INTRODUCTION + This manual, how to use it, and its terms + + I have seen a lot of requests lately on USENET for LPC manuals. In addition, + the immortals on my mud have been telling how good the building documentation + of Nightmare is, but that there was just no adequate explanation of the + LPC programming language. So I decided to try my hand at writing a manual. + Some things you should keep in mind. + LPC is a very easy programming language to learn, and it has real + value in that place most of us know as the real world. I began playing + muds in 1991, and in the space of a month created an unimpressive area + and musician's guild on the original Bates College MUD called Orlith. + After that, I moved to Los Angeles for a year and had no contact with + mudding or computers. In June of 1992, I was back on the internet and + a wizard of Igor. In September of 1992 I began coding the Nightmare + mudlib for our use, and then later decided to distribute it due to there + not being any mudlibs for MudOS at the time that a person could just throw + up a running mud with (now, that of course is not the case :)). + So, I have been doing serious coding for less than a year. As a + Philosophy major in a world of Computer Science majors, I just want to + make clear that it is not at all required that you have ever done anything + with your computer than log into a mud in order for you to really come + to understand LPC coding. This manual makes the following assumptions: + Someone has taught you basic UNIX commands like ls, cd, mkdir, mv, rm, etc. + You know how to enter your mud's editor and write a file. No other + assumptions are made. If you know C, you are handicapped in that LPC + looks a lot like C, but it is not C. Your preconceptions about + modular programming development will be a hinderence you will have to + overcome. If you have never heard of the C programming language (like + me in May of 1991), then you are only missing an understanding of the + simple constructs of C like the flow of program execution and logical + operators and such. So a C guru has no real advantage over you, since + what they know from C which is applicable to LPC is easy to pick up. + The stuff they know about C which makes them a guru is irrelevant to + LPC. + + The chapters of this manual are meant to be read in order. Starting with + the introduction, going sequentially through the chapter numbers as + ordered in the contents file. Each chapter begins with a paragraph or + two explaining what you should have come to understand by that point + in your studies. After those introductory paragraphs, the chapter then + begins to discuss its subject matter in nauseating detail. At the end + of the chapter is a briefly worded summary of what you should understand + from that chapter if I have been successful. Following that may or may + not be some sidenotes relevant to the subject at hand, but not necessary + to its understanding. + + If at any time you get to a chapter intro, and you have read the preceeding + chapters thoroughly and you do not understand what it says you should + understand by that point, please mail me! Clearly, I have failed at that + point and I need to know where it is I have gone wrong so I can revise + it properly. Similarly, if you do not understand what the chapter summary + says you should, please mail me. If your mumud is on the MudOS intermud + system, mail descartes@nightmare. Otherwise mail borg@hebron.connected.com. + + Some basic terms this manual uses: + driver- + This is the C program which is the game. It accepts incoming sockets + (links to other computers), interprets LPC code defined by the mudlib, + keeps mud objects in memory, makes periodic attempts to clean unused + mud objects from memory, makes periodic calls to objects, and so on. + + mudlib- + LPC code which defines the world in which you are in. The driver of itself + is not a game. It is just a program which allows the creation of a + multi-user environment. In some sense, the driver is like an LPC + compiler, and the mudlib is like a compiler's library (a very loose + analogy). The mudlib defines basic objects which will likely be used + over and over again by people creating in the mud world. Examples of + such objects are /std/room (or /room/room), /std/user.c (or /obj/player.c), + and so on. + + area or castle: + Specific creator coded objects which often use a feature of LPC called + inheritance to make use of the properties of basic mudlib objects and + turn them into specific objects to be used by players in the game + + object: + a room, a weapon, a monster, a player, a bag, etc. More importantly, + every individual file with a .c extension is an object. Objects are + used in different ways. Objects like /std/living.c are inherited by + objects like monster.c and user.c. Others are cloned, which means a + duplicate of that code is loaded into memory. And still others are + simply loaded into memory to be referenced by other objects. + + native and compat: + these two terms refer to two popular flavours of drivers. Native mode + mudlibs make use of on the design of LPMud driver 3.0 and later. You may + have a 3.0 driver however, but have a 2.4.5 style mudlib. This is what + is meant by compat mode. Mudlibs which are native mode are any for + MudOS, CD, and LPMud mudlibs that + are listed as native. Compat mudlibs are any LPMud mudlib before 3.0 and + those which are 3.* compat mudlibs. I believe Amylaar's is compat. + + Good Luck! + George Reese + (Descartes of Borg) + 12 july 1993 + borg@hebron.connected.com diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter1 ds2.1/lib/doc/lpc/basic/chapter1 *** ds1.1/lib/doc/lpc/basic/chapter1 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter1 Wed Jul 5 00:01:10 2006 *************** *** 0 **** --- 1,90 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 25 may 1993 + + CHAPTER 1: Introduction to the Coding Environment + + 1.1 UNIX file structure + LPMuds use basic UNIX commands and its file structure. If you know + UNIX commands already, then note (with a few exceptions) options are + not available to the commands. Like DOS, UNIX is heirarchical. The + root directory of which all directories are sub-directories is called + root(/). And from those sub-directories you may have further + sub-directories. A directory may be referred to in two different ways: + 1) by its full name, or absolute name, or 2) by its relative name. + Absolute name refers to the directory's full path starting from / winding + down the directory tree until you name the directory in question. For + example: + + /players/descartes/obj/monster + + refers to the directory monster which is a sub-directory of obj which + is a sub-directory of descartes which is a sub-directory of players + which is a sudirectory of /. + + The relative name refers to the name relative to another directory. + The above example is called monster relative to /players/descartes/obj, + but it is also called obj/monster relative to /players/descartes, + descartes/obj/monster relative to /players, and finally + players/descartes/obj/monster relative to /. You can tell the + difference between absolute names and relative names because absolute + names always start with /. In order to know exactly which directory + is being named by a relative name, you naturally must know what + directory it is relative to. + + A directory contains sub-directories and files. LPMuds only use text files + inside the mudlib. Like directories, files have both absolute and + relative names. The most basic relative name is often referred to as the file + name, with the rest of the absolute name being referred to as the path. So, + for the file: /players/descartes/castle.c, castle.c is the file name, and + /players/descartes is the path. + + On some muds, a file with a file name beginning with a . (like .plan) is + not visible when you list files with the regular file listing command. + + 1.2 UNIX Commands + Along with the UNIX file structure, LPMuds use many UNIX commands. Typical + UNIX commands on most muds are: + pwd, cd, ls, rm, mv, cp, mkdir, rmdir, more, head, cat, ed + If you have never before seen UNIX commands, you probably are thinking this + is all nonsense. Well, it is, but you got to use them. Before getting + into what they mean though, first a discussion of current directory. + If you know DOS, then you know what a current working directory is. + At any given point, you are considered to be "in" some directory. This + means that any relative file or directory names you give in UNIX commands + are relative to that directory. For example, if my current directory is + /players/descartes and I type "ed castle.c" (ed is the command to edit), + then it assumes I mean the file /players/descartes/castle.c + + pwd: shows you your current working directory + cd: changes your current working directory. You may give either relative + or absolute path names. With no arguments, it changes to your home + directory. + ls: lists all files in the directory named. If no directory is named, + it lists the files of the current working directory + rm: deletes the file named + mv: renames the file named + cp: copies the file named + mkdir: makes a new directory + rmdir: deletes a directory. All files must have been first removed. + more: pages the file named so that the file appears on your screen one + page at a time. + cat: shows the whole file to you at once + head: shows you the first several lines of a file + tail: shows you the last several lines of a file + ed: allows you to edit a file using the mud editor + + 1.3 Chapter Summary + UNIX uses a heirarchical file structure with the root of the tree being + named /. Other directories branch off from that root directory and + in turn have their own sub-directories. All directories may contain + directories and files. Directories and files are referred to either + by their absolute name, which always begins with /, or by their relative + name which gives the file's name relative to a particular directory. + In order to get around in the UNIX files structure, you have the + typical UNIX commands for listing files, your current directory, etc. + On your mud, all of the above commands should have detailed help commands + to help you explore exactly what they do. In addition, there should + be a very detailed file on your mud's editor. If you are unfamiliar + with ed, you should go over this convoluted file. diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter2 ds2.1/lib/doc/lpc/basic/chapter2 *** ds1.1/lib/doc/lpc/basic/chapter2 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter2 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,195 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 16 june 1993 + + CHAPTER 2: The LPC Program + + 2.1 About programs + The title of this chapter of the textbook is actually poorly named, since + one does not write programs in LPC. An LPC coder instead writes *objects*. + What is the difference? Well, for our purposes now, the difference is + in the way the file is executed. When you "run" a program, execution + begins at a definite place in the program. In other words, there + is a place in all programs that is noted as the beginning where program + execution starts. In addition, programs have definite end points, + so that when execution reaches that point, the execution of the program + terminates. So, in short, execution of a program runs from a definite + beginning point through to a definite end point. This is not so with + LPC objects. + + With muds, LPC objects are simply distinct parts of the C program which + is running the game (the driver). In other words, execution of the mud + program begins and ends in the driver. But the driver in fact does + very little in the way of creating the world you know when you play + a mud. Instead, the driver relies heavily on the code created in LPC, + executing lines of the objects in the mud as needed. LPC objects thus + have no place that is necessarily the beginning point, nor do they + have a definite ending point. + + Like other programming languages, an LPC "program" may be made up of + one or more files. For an LPC object to get executed, it simple + needs to be loaded into the driver's memory. The driver will call lines + from the object as it needs according to a structure which will be + defined throughout this textbook. The important thing you need to + understand at this point is that there is no "beginning" to an LPC + object in terms of execution, and there is no "end". + + 2.2 Driver-mudlib interaction + As I have mentioned earlier, the driver is the C program that runs on + the host machine. It connects you into the game and processes LPC code. + Note that this is one theory of mud programming, and not necessarily + better than others. It could be that the entire game is written in C. + Such a game would be much faster, but it would be less flexible in + that wizards could not add things to the game while it was running. This + is the theory behind DikuMUDs. Instead, LPMUDs run on the theory that + the driver should in no define the nature of the game, that the nature + of the game is to be decided by the individuals involved, and that + you should be able to add to the game *as it is being played*. This + is why LPMUDs make use of the LPC programming language. It allows + you to define the nature of the game in LPC for the driver to read and + execute as needed. It is also a much simpler language to understand + than C, thus making the process of world creation open to a greater + number of people. + + Once you have written a file in LPC (assuming it is corrent LPC ), it justs + sits there on the host machine's hard drive until something in the game + makes reference to it. When something in the game finally does make + reference to the object, a copy of the file is loaded into memory and + a special *function* of that object is called in order to initialize + the values of the variables in the object. Now, do not be concerned + if that last sentence went right over your head, since someone brand + new to programming would not know what the hell a function or a variable + is. The important thing to understand right now is that a copy of the + object file is taken by the driver from the machine's hard drive and + stored into memory (since it is a copy, multiple versions of that + object may exist). You will later understand what a function is, what + a variable is, and exactly how it is something in the game made reference + to your object. + + 2.3 Loading an object into memory + Although there is no particular place in an object code that must exist + in order for the driver to begin executing it, there is a place for which + the driver will search in order to initialize the object. On compat + drivers, it is the function called reset(). On native muds it is the + function called create(). + + LPC objects are made up of variables (values which can change) and + functions which are used to manipulate those variables. Functions + manipulate variables through the use of LPC grammatical structures, + which include calling other functions, using externally defined + functions (efuns), and basic LPC expressions and flow control + mechanisms. + + Does that sound convoluted? First lets start with a variable. A + variable might be something like: level. It can "vary" from sitation + to situation in value, and different things use the value of the player's + level to make different things happen. For instance, if you are a + level 19 player, the value of the variable level will be 19. Now + if your mud is on the old LPMud 2.4.5 system where levels 1-19 are + players and 20+ are wizards, things can ask for your level value to + see if you can perform wizard type actions. Basically, each object + in LPC is a pile of variables with values which change over time. + Things happen to these objects based on what values its variables + hold. Often, then things that happen cause the variables to change. + + So, whenever an object in LPC is referenced by another object currently + in memory, the driver searches to see what places for values the + object has (but they have no values yet). Once that is done, the driver + calls a function in the object called reset() or create() (depending + on your driver) which will set up the starting values for the object's + variables. It is thus through *calls* to *functions* that variable + values get manipulated. + + But create() or reset() is NOT the starting place of LPC code, although + it is where most LPC code execution does begin. The fact is, those + functions need not exist. If your object does just fine with its + starting values all being NULL pointers (meaning, for our purposes + here, 0), then you do not need a create() or reset() function. Thus + the first bit of execution of the object's code may begin somewhere + completely different. + + Now we get to what this chapter is all about. The question: What + consists a complete LPC object? Well, an LPC object is simply + one or more functions grouped together manipulating 0 or more + variables. The order in which functions are placed in an object + relative to one another is irrelevant. In other words: + + ----- + void init() { add_action("smile", "smile"); } + + void create() { return; } + + int smile(string str) { return 0; } + ----- + + is exactly the same as: + + ----- + void create() { return; } + + int smile(string str) { return 0; } + + void init() { add_action("smile", "smile"); } + _____ + + Also important to note, the object containing only: + + ----- + void nonsense() {} + ----- + + is a valid, but trivial object, although it probably would not interact + properly with other objects on your mud since such an object has no + weight, is invisible, etc.. + + 2.4 Chapter summary + LPC code has no beginning point or ending point, since LPC code is used + to create objects to be used by the driver program rather than create + individual programs. LPC objects consist of one or more functions whose + order in the code is irrelevant, as well as of zero or more variables whose + values are manipulated inside those functions. LPC objects simply sit + on the host machine's hard driver until referenced by another object in + the game (in other words, they do not really exist). Once the object + is referenced, it is loaded into the machine's memory with empty + values for the variables. The function reset() in compat muds or + create() in native muds is called in that object if it exists to allow + the variables to take on initial values. Other functions in the object + are used by the driver and other objects in the game to allow interaction + among objects and the manipulation of the LPC variables. + + A note on reset() and create(): + create() is only used by muds in native mode (see the textbook Introduction + for more information on native mode vs. compat mode). It is only used + to initialize newly referenced objects. + + reset() is used by both muds in compat mode and native mode. In compat + mode, reset() performs two functions. First, it is used to initialize + newly referenced objects. In addition, however, compat mode muds use + reset() to "reset" the object. In other words, return it to its initial + state of affairs. This allows monsters to regenerate in a room and doors + to start back in the shut position, etc.. Native mode muds use reset() + to perform the second function (as its name implies). + + So there are two important things which happen in LP style muds which + cause the driver to make calls to functions in objects. The first is + the creation of the object. At this time, the driver calls a function + to initalize the values in the object. For compat mode muds, this + is performed by the function named reset() (with an argument of 0, + more on this later though). For muds running in native mode, this is + performed by the function create(). + + The second is the returning of the room to some base state of affairs. + This base set of affairs may or may not be different from the initial + state of affairs, and certainly you would not want to take up time + doing redundant things (like resetting variables that never change). + Compat mode muds nevertheless use the same function that was used to + create the object to reset it, that being reset(). Native mode muds, + who use create() to create the room, instead use reset() to reset it. + All is not lost in compat mode though, as there is a way to tell the + difference between creation and resetting. For reset purposes, the + driver passes either 1 or the reset number as an argument to reset() + in compat mode. Now this is meaningless to you now, but just keep in + mind that you can in fact tell the difference in compat mode. Also + keep in mind that the argment in the creation use of reset is 0 and + the argument in the reset use is a nonzero number. diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter3 ds2.1/lib/doc/lpc/basic/chapter3 *** ds1.1/lib/doc/lpc/basic/chapter3 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter3 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,185 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 17 june 1993 + + CHAPTER 3: LPC Data Types + + 3.1 What you should know by now + LPC object are made up of zero or more variables manipulated by one or + more functions. The order in which these functions appear in code is + irrelevant. The driver uses the LPC code you write by loading copies of + it into memory whenever it is first referenced and additional copies + through cloning. When each object is loaded into memory, all the variables + initially point to no value. The reset() function in compat muds, and + create() in native muds are used to give initial values to variables in + objects. The function for creation is called immediately after the object + is loaded into memory. However, if you are reading this textbook with no + prior programming experience, you may not know what a function is or how + it gets called. And even if you have programming experience, you may + be wondering how the process of functions calling each other gets started + in newly created objects. Before any of these questions get answered, + however, you need to know more about what it is the functions are + manipulating. You therefore should thouroughly come to know the concept + behind LPC data types. Certainly the most boring subject in this manual, + yet it is the most crucial, as 90% of all errors (excepting misplaced + {} and ()) involve the improper usage of LPC data types. So bear through + this important chapter, because it is my feeling that understanding this + chapter alone can help you find coding much, much easier. + + 3.2 Communicating with the computer + You possibly already know that computers cannot understand the letters + and numbers used by humans. Instead, the "language" spoken by computers + consists of an "alphabet" of 0's and 1's. Certainly you know computers + do not understand natural human languages. But in fact, they do not + understand the computer languages we write for them either. Computer + languages like BASIC, C, C++, Pascal, etc. are all intermediate + languages. They allow you to structure your thoughts more coherently + for translation into the 0's and 1's of the computer's languages. + + There are two methods in which translation is done: compilation and + interpretation. These simply are differences betweem when the + programming language is translated into computer language. With + compiled languages, the programmer writes the code then uses a program + called a compiler to translate the program into the computer's + language. This translation occurs before the program is run. With + interpreted languages however, the process of translation occurs as + the program is being run. Since the translation of the program is + occurring during the time of the program's running in interpreted + languages, interpreted languages make much slower programs than + compiled languages. + + The bottom line is, no matter what language you are writing in, at + some point this has to be changed into 0's and 1's which can be + understood by the computer. But the variables which you store in + memory are not simply 0's and 1's. So you have to have a way in + your programming languages of telling the computer whether or not + the 0's and 1's should be treated as decimal numbers or characters or + strings or anything else. You do this through the use of data types. + + For example, say you have a variable which you call 'x' and you give + it the decimal whole number value 65. In LPC you would do this through + the statement: + + ----- + x = 65; + ----- + + You can later do things like: + + _____ + write(x+"\n"); /* \n is symbolically represents a carriage return */ + y = x + 5; + ----- + + The first line allows you to send 65 and a carriage return to someone's screen. + The second line lets you set the value of y to 70. + The problem for the computer is that it does not know what '65' means when + you tell it x = 65;. What you think of 65, it might think of as: + 00000000000000000000000001000001 + But, also, to the computer, the letter 'A' is represented as: + 00000000000000000000000001000001 + So, whenever you instruct the computer write(x+"\n");, it must have some + way of knowing that you want to see '65' and not 'A'. + + The computer can tell the difference between '65' and 'A' through the use + of data types. A data types simply says what type of data is being stored + by the memory location pointed to by a given variable. Thus, each LPC + variable has a variable type which guides conversions. In the example + given above, you would have had the following line somewhere in the + code *before* the lines shown above: + + ----- + int x; + ----- + + This one line tells the driver that whatever value x points to, it will + be used as the data type "int", which is short for integer, or whole + number. So you have a basic introduction into the reason why data types + exist. They exist so the driver can make sense of the 0's and 1's that + the computer is storing in memory. + + 3.3 The data types of LPC + All LPMud drivers have the following data types: + + void, status, int, string, object, int *, string *, object *, mixed * + + Many drivers, but not all have the following important data types which + are important to discuss: + + float, mapping, float *, mapping * + + And there are a few drivers with the following rarely used data types + which are not important to discuss: + + function, enum, struct, char + + 3.4 Simple data types + This introductory textbook will deal with the data types void, status, + int, float, string, object, mand mixed. You can find out about the + more complex data types like mappings and arrays in the intermediate + textbook. This chapter deals with the two simplest data types (from the + point of view of the LPC coder), int and string. + + An int is any whole number. Thus 1, 42, -17, 0, -10000023 are all type int. + A string is one or more alphanumeric characters. Thus "a", "we are borg", + "42", "This is a string" are all strings. Note that strings are always + enclosed in "" to allow the driver to distinguish between the int 42 and + the string "42" as well as to distinguish between variable names (like x) + and strings by the same names (like "x"). + + When you use a variable in code, you must first let the driver know + what type of data to which that variable points. This process is + called *declaration*. You do this at the beginning of the function + or at the beginning of the object code (outside of functions before all + functions which use it). This is done by placing the name of the data type + before the name of the variable like in the following example: + + ----- + void add_two_and_two() { + int x; + int y; + + x = 2; + y = x + x; + } + ----- + + Now, this is a complete function. The name of the function is + add_two_and_two(). The function begins with the declaration of an + int variable named x followed by the declaration of an in variable + named y. So now, at this point, the driver now has two variables which + point to NULL values, and it expects what ever values end up there to be + of type int. + + A note about the data types void and status: + Void is a trivial data type which points to nothing. It is not used + with respect to variables, but instead with respect to functions. You + will come to understand this better later. For now, you need only + understand that it points to no value. + + The data type status is a boolean data type. That is, it can only have + 1 or 0 as a value. This is often referred to as being true or false. + + 3.5 Chapter summary + For variables, the driver needs to know how the 0's and 1's the computer + stores in memory get converted into the forms in which you intend them + to be used. The simplest LPC data types are void, status, int, and string. + You do not user variables of type void, but the data type does come + into play with respect to functions. In addition to being used for + translation from one form to the next, data types are used in determining + what rules the driver uses for such operations as +, -, etc. For example, + in the expression 5+5, the driver knows to add the values of 5 and 5 + together to make 10. With strings however, the rules for int addition + make no sense. So instead, with "a"+"b", it appends "b" to the string "a" + so that the final string is "ab". Errors can thus result if you mistakenly + try to add "5"+5. Since int addition makes no sense with strings, the + driver will convert the second 5 to "5" and use string addition. The final + result would be "55". If you were looking for 10, you would therefore + have ended up with erroneous code. Keep in mind, however, that in most + instances, the driver will not do something so useful as coming up with + "55". It comes up with "55" cause it has a rule for adding a string + to an int, namely to treat the int as a string. In most cases, if you + use a data type for which an operation or function is not defined + (like if you tried to divide "this is" by "nonsense", "this is"/"nonsense"), + the driver will barf and report an error to you. diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter4 ds2.1/lib/doc/lpc/basic/chapter4 *** ds1.1/lib/doc/lpc/basic/chapter4 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter4 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,225 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 22 june 1993 + + CHAPTER 4: Functions + + 4.1 Review + By this point, you should be aware that LPC objects consist of functions + which manipulate variables. The functions manipulate variables when they + are executed, and they get executed through *calls* to those functions. + The order in which the functions are placed in a file does not matter. + Inside a function, the variables get manipulated. They are stored in + computer memory and used by the computer as 0's and 1's which + get translated to and from useable output and input through a device + called data typing. String data types tell the driver that the + data should appear to you and come from you in the form of alphanumeric + characters. Variables of type int are represented to you as whole + number values. Type status is represented to you as either 1 or 0. + And finally type void has no value to you or the machine, and is not + really used with variable data types. + + 4.2 What is a function? + Like math functions, LPC functions take input and return output. + Languages like Pascal distinguish between the concept of proceedure abd + the concept of function. LPC does not, however, it is useful to + understand this distinction. What Pascal calls a proceedure, LPC + calls a function of type void. In other words, a proceedure, or function + of type void returns no output. What Pascal calls a function differs + in that it does return output. In LPC, the most trivial, correct + function is: + + ----- + void do_nothing() { } + ----- + + This function accepts no input, performs no instructions, and returns no + value. + + There are three parts to every properly written LPC function: + 1) The declaration + 2) The definition + 3) The call + + Like with variables, functions must be declared. This will allow the + driver to know 1) what type of data the function is returning as output, + and 2) how many input(s) and of what type those input(s) are. The + more common word for input is parameters. + A function declaration therefore consists of: + type name(parameter1, parameter2, ..., parameterN); + The declaration of a function called drink_water() which accepts a string as + input and an int as output would thus look like this: + + ----- + int drink_water(string str); + ----- + + where str is the name of the input as it will be used inside the function. + + The function definition is the code which describes what the function actually + does with the input sent to it. + The call is any place in other functions which invokes the execution of the + function in question. For two functions write_vals() and add(), you thus + might have the following bit of code: + + ----- + /* First, function declarations. They usually appear at the beginning + of object code. + */ + void write_vals(); + int add(int x, int y); + + /* Next, the definition of the function write_vals(). We assume that + this function is going to be called from outside the object + */ + void write_vals() { + int x; + + /*N Now we assign x the value of the output of add() through a call */ + x = add(2, 2); + write(x+"\n"); + } + + /* Finally, the definition of add() */ + int add(int x, int y) { + return (x + y); + } + ----- + + Remember, it does not matter which function definition appears first in the + code. This is because functions are not executed consecutively. Instead, + functions are executed as called. The only requirement is that the + declaration of a function appear before its definition and before the + definition of any function which makes a call to it. + + 4.3 Efuns + Perhaps you have heard people refer to efuns. They are externally defined + functions. Namely, they are defined by the mud driver. If you have + played around at all with coding in LPC, you have probably found some + expressions you were told to use like this_player(), write(), say(), + this_object(), etc. look a lot like functions. That is because they are + efuns. The value of efuns is that they are much faster than LPC functions, + since they already exist in the binary form the computer understands. + + In the function write_vals() above, two functions calls were made. The first was to + the functions add(), which you declared and defined. The second call, however, + was to a function called write(), and efun. The driver has already declared + and defined this function for you. You needs only to make calls to it. + + Efuns are created to hanldle common, every day function calls, to handle + input/output to the internet sockets, and other matters difficult to be + dealt with in LPC. They are written in C in the game driver and compiled + along with the driver before the mud comes up, making them much faster + in execution. But for your purposes, efun calls are just like calls + made to your functions. Still, it is important to know two things of any + efun: 1) what return type does it have, and 2) what parameters of what + types does it take. + + Information on efuns such as input parameters and return types is often + found in a directory called /doc/efun on your mud. I cannot + detail efuns here, because efuns vary from driver to driver. However, + you can often access this information using the commands "man" or "help" + depending on your mudlib. For instance, the command "man write" would + give you information on the write efun. But if all else fails, + "more /doc/efun/write" should work. + + By looking it up, you will find write is declared as follows: + + ----- + void write(string); + ----- + + This tells you an appropriate call to write expects no return value and + passes a single parameter of type string. + + 4.4 Defining your own functions + Although ordering your functions within the file does not matter, ordering + the code which defines a function is most important. Once a function + has been called, function code is executed in the order it appears + in the function definition. In write_vals() above, the instruction: + + ----- + x = add(2, 2); + ----- + + Must come before the write() efun call if you want to see the appropriate + value of x used in write(). + + With respect to values returned by function, this is done through the "return" + instruction followed by a value of the same data type as the function. In + add() above, the instruction is "return (x+y);", where the value of (x+y) + is the value returned to write_vals() and assigned to x. On a more + general level, "return" halts the execution of a function and returns + code execution to the function which called that function. In addition, + it returns to the calling function the value of any expression that follows. + To stop the execution of a function of type void out of order, use + "return"; without any value following. Once again, remember, the data + type of the value of any expression returned using "return" MUST be the + same as the data type of the function itself. + + 4.5 Chapter Summary + The files which define LPC objects are made of of functions. Functions, in + turn, are made up of three parts: + 1) The declaration + 2) The definition + 3) The call + Function declarations generally appear at the top of the file before any + defintions, although the requirement is that the declaration must appear + before the function definition and before the definition of any function + which calls it. + Function definitions may appear in the file in any order so long as they + come after their declaration. In addition, you may not define one function + inside another function. + Function calls appear inside the definition of other functions where you + want the code to begin execution of your function. They may also appear + within the definition of the function itself, but this is not recommended + for new coders, as it can easily lead to infinite loops. + + The function definition consists of the following in this order: + 1) function return type + 2) function name + 3) opening ( followed by a parameter list and a closing ) + 4) an opening { instructing the driver that execution begins here + 5) declarations of any variables to be used only in that function + 6) instructions, expressions, and calls to other functions as needed + 7) a closing } stating that the function code ends here and, if no + "return" instruction has been given at this point (type void functions + only), execution returns to the calling function as if a r"return" + instruction was given + + The trivial function would thus be: + + ----- + void do_nothing() {} + ----- + + since this function does not accept any input, perform any instructions, or + return any output. + + Any function which is not of type void MUST return a value of a data type + matching the function's data type. + + Each driver has a set of functions already defined for you called efuns + These you need neither need to declare nor define since it has already + been done for you. Furthermore, execution of these functions is faster + than the execution of your functions since efuns are in the driver. + In addition, each mudlib has special functions like efuns in that they + are already defined and declared for you, but different in that they + are defined in the mudlib and in LPC. They are called simul_efuns, or + simulated efuns. You can find out all about each of these as they are + listed in the /doc/efun directory on most muds. In addition many + muds have a command called "man" or a "help" command which allows you + simply to call up the info files on them. + + Note on style: + Some drivers may not require you to declare your functions, and some + may not require you to specify the return type of the function in its + definition. Regardless of this fact, you should never omit this information + for the following reasons: + 1) It is easier for other people (and you at later dates) to read your + code and understand what is meant. This is particularly useful + for debugging, where a large portion of errors (outside of misplaced + parentheses and brackets) involve problems with data types (Ever + gotten "Bad arg 1 to foo() line 32"?). + 2) It is simply considered good coding form. diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter5 ds2.1/lib/doc/lpc/basic/chapter5 *** ds1.1/lib/doc/lpc/basic/chapter5 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter5 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,161 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 01 july 1993 + + CHAPTER 5: The Basics of Inheritance + + 5.1 Review + You should now understand the basic workings of functions. You should be + able to declare and call one. In addition, you should be able to recognize + function definitions, although, if this is your first experience with LPC, + it is unlikely that you will as yet be able to define your own functions. + There functions form the basic building blocks of LPC objects. Code + in them is executed when another function makes a call to them. In making + a call, input is passed from the calling function into the execution of + the called one. The called function then executes and returns a value + of a certain data type to the calling function. Functions which return + no value are of type void. + + After examining your workroom code, it might look something like this + (depending on the mudlib): + + ----- + inherit "/std/room"; + + void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + set("short", "Descartes' Workroom"); + set("long", "This is where Descartes works.\nIt is a cube.\n"); + SetExits( ({ "/domains/standard/square" }), ({ "square" }) ); + } + ----- + + If you understand the entire textbook to this point, you should recognize + of the code the following: + 1) create() is the definition of a function (hey! he did not declare it) + 2) It makes calls to SetProperty(), set(), and SetExits(), none + of which are declared or defined in the code. + 3) There is a line at the top that is no variable or function declaration + nor is it a function definition! + + This chapter will seek to answer the questions that should be in your head + at this point: + 1) Why is there no declaration of create()? + 2) Where are the functions SetProperty(), set(), and SetExits() declared + and defined? + 3) What the hell is that line at the top of the file? + + 5.2 Object oriented programming + Inheritance is one of the properties which define true object oriented + programming (OOP). It allows you to create generic code which can be used + in many different ways by many different programs. What a mudlib does is + create these generalized files (objects) which you use to make very specific + objects. + + If you had to write the code necessary for you to define the workroom above, + you would have to write about 1000 lines of code to get all the functionality + of the room above. Clearly that is a waste of disk space. In addition, + such code does not interact well with players and other rooms since every + creator is making up his or her own functions to perform the functionality + of a room. Thus, what you might use to write out the room's long description, + GetLong(), another wizard might be calling long(). This is the primary + reason mudlibs are not compatible, since they use different protocols for + object interaction. + + OOP overcomes these problems. In the above workroom, you inherit the + functions already defined in a file called "/std/room.c". It has all + the functions which are commonly needed by all rooms defined in it. When + you get to make a specific room, you are taking the general functionality + of that room file and making a unique room by adding your own function, + create(). + + 5.3 How inheritance works + As you might have guessed by now, the line: + + ----- + inherit "/std/room"; + ----- + + has you inherit the functionality of the room "/std/room.c". By inheriting + the functionality, it means that you can use the functions which have + been declared and defined in the file "/std/room.c" In the Nightmare Mudlib, + "/std/room.c" has, among other functions, SetProperty(), set(), and + SetExits() declared and defined. In your function create(), you are + making calls to those functions in order to set values you want your + room to start with. These values make your room different from others, yet + able to interact well with other objects in memory. + + In actual practice, each mudlib is different, and thus requires you to use + a different set of standard functions, often to do the same thing. It is + therefore beyond the scope of this textbook even to describe what + functions exist and what they do. If your mudlib is well documented, + however, then (probably in /doc/build) you will have tutorials on how + to use the inheritable files to create such objects. These tutorials + should tell you what functions exist, what input they take, the data + type of their output, and what they do. + + 5.4 Chapter summary + This is far from a complete explanation of the complex subject of inheritance. + The idea here is for you to be able to understand how to use inheritance in + creating your objects. A full discussion will follow in a later textbook. + Right now you should know the following: + 1) Each mudlib has a library of generic objects with their own general + functions used by creators through inheritance to make coding objects + easier and to make interaction between objects smoother. + 2) The functions in the inheritable files of a mudlib vary from mudlib + to mudlib. There should exist documentation on your mud on how to + use each inheritable file. If you are unaware what functions are + available, then there is simply no way for you to use them. Always + pay special attention to the data types of the input and the data + types of ay output. + 3) You inherit the functionality of another object through the line: + + ----- + inherit "filename"; + ----- + + where filename is the name of the file of the object to be inherited. + This line goes at the beginning of your code. + + Note: + You may see the syntax ::create() or ::init() or ::reset() in places. + You do not need fully to understand at this point the full nuances of this, + but you should have a clue as to what it is. The "::" operator is a way + to call a function specifically in an inherited object (called the scope + resolution operator). For instance, most muds' room.c has a function + called create(). When you inherit room.c and configure it, you are doing + what is called overriding the create() function in room.c. This means + that whenever ANYTHING calls create(), it will call *your* version and not + the one in room.c. However, there may be important stuff in the room.c + version of create(). The :: operator allows you to call the create() in + room.c instead of your create(). + An example: + + ----- + #1 + + inherit "/std/room"; + + void create() { create(); } + ----- + + ----- + #2 + + inherit "/std/room"; + + void create() { ::create(); } + ----- + + Example 1 is a horror. When loaded, the driver calls create(), and then + create() calls create(), which calls create(), which calls create()... + In other words, all create() does is keep calling itself until the driver + detects a too deep recursion and exits. + + Example 2 is basically just a waste of RAM, as it is no different from room.c + functionally. With it, the driver calls its create(), which in turn calls + ::create(), the create() in room.c. Otherwise it is functionally + exactly the same as room.c. diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter6 ds2.1/lib/doc/lpc/basic/chapter6 *** ds1.1/lib/doc/lpc/basic/chapter6 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter6 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,333 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: july 5 1993 + + CHAPTER 6: Variable Handling + + 6.1 Review + By now you should be able to code some simple objects using your muds standard + object library. Inheritance allows you to use functions defined in those + objects without having to go and define yourself. In addition, + you should know how to declare your own functions. This + chapter will teach you about the basic elements of LPC which will allow you to + define your own functions using the manipulation of variables. + + 6.2 Values and objects + Basically, what makes objects on the mud different are two things: + 1) Some have different functions + 2) All have different values + + Now, all player objects have the same functions. They are therefore + differentiated by the values they hold. For instance, the player + named "Forlock" is different from "Descartes" *at least* in that they + have different values for the variable true_name, those being + "descartes" and "forlock". + + Therefore, changes in the game involve changes in the values of the objects + in the game. Functions are used to name specific process for manipulating + values. For instance, the create() function is the function whose + process is specifically to initialize the values of an object. + Within a function, it is specifically things called instructions which are + responsible for the direct manipulation of variables. + + 6.3 Local and global variables + Like variables in most programming language, LPC variables may be declared + as variables "local" to a specific function, or "globally" available + to all functions. Local variables are declared inside the function which + will use them. No other function knows about their existence, since + the values are only stored in memory while that function is being executed. + A global variable is available to any function which comes after its + declaration in the object code. Since global variables take up RAM for + the entire existence of the object, you should use them only when + you need a value stored for the entire existence of the object. + Have a look at the following 2 bits of code: + + ----- + int x; + + int query_x() { return x; } + + void set_x(int y) { x = y; } + ----- + + ----- + void set_x(int y) { + int x; + + x = y; + write("x is set to x"+x+" and will now be forgotten.\n"); + } + ----- + + In the first example, x is declared outside of any functions, and therefore + will be available to any function declared after it. In that example, + x is a global variable. + In the second example, x is declared inside the function set_x(). It + only exists while the function set_x() is being executed. Afterwards, + it ceases to exist. In that example, x is a local variable. + + 6.4 Manipulating the values of variables + Instructions to the driver are used to manipulate the values of variables. + An example of an instruction would be: + + ----- + x = 5; + ----- + + The above instruction is self-explanatory. It assigns to the variable + x the value 5. However, there are some important concepts in involved + in that instruction which are involved in instructions in general. + The first involves the concept of an expression. An expression is + any series of symbols which have a value. In the above instruction, + the variable x is assigned the value of the expression 5. Constant + values are the simplest forms in which expressions can be put. A constant + is a value that never changes like the int 5 or the string "hello". + The last concept is the concept of an operator. In the above example, + the assignment operator = is used. + + There are however many more operators in LPC, and expressions can get + quite complex. If we go up one level of complexity, we get: + + ----- + y = 5; + x = y +2; + ----- + + The first instruction uses the assignment operator to assign the value + of the constant expression 5 to the variable y. The second one + uses the assignment operator to assign to x the value of the expression + (y+2) which uses the addition operator to come up with a value which + is the sum of the value of y and the value of the constant expression 2. + Sound like a lot of hot air? + + In another manner of speaking, operators can be used to form complex + expressions. In the above example, there are two expressions in the + one instruction x = y + 2;: + 1) the expression y+2 + 2) the expression x = y + 2 + As stated before, all expressions have a value. The expression + y+2 has the value of the sum of y and 2 (here, 7); + The expression x = y + 2 *also* has the value of 7. + So operators have to important tasks: + 1) They *may* act upon input like a function + 2) They evaluate as having a value themselves. + Now, not all operators do what 1 does. The = operators does act upon + the value of 7 on its right by assigning that value to x. The operator + + however does nothing. They both, however, have their own values. + + 6.5 Complex expressions + As you may have noticed above, the expression x = 5 *itself* has a value + of 5. In fact, since LPC operators themselves have value as expressions, + they cal allow you to write some really convoluted looking nonsense like: + i = ( (x=sizeof(tmp=users())) ? --x : sizeof(tmp=children("/std/monster"))-1) + which says basically: + assing to tmp the array returned by the efun users(), then assign to x + the value equal to the number of elements to that array. If the value + of the expression assigning the value to x is true (not 0), then assign + x by 1 and assign the value of x-1 to i. If x is false though, + then set tmp to the array returned by the efun children(), and then + assign to i the value of the number of members in the array tmp -1. + Would you ever use the above statement? I doubt it. However you might + see or use expressions similar to it, since the ability to consolidate + so much information into one single line helps to speed up the execution of + your code. A more often used version of this property of LPC operators + would be something like: + x = sizeof(tmp = users()); + while(i--) write((string)tmp[i]->GetKeyName()+"\n"); + instead of writing something like: + tmp = users(); + x = sizeof(tmp); + for(i=0; i<x; i++) write((string)tmp[i]->GetKeyName()+"\n"); + Things like for(), while(), arrays and such will be explained later. + But the first bit of code is more concise and it executed faster. + + NOTE: A detailed description of all basic LPC operators follows the chapter + summary. + + + 6.6 Chapter Summary + You now know how to declare variables and understand the difference between + declaring and using them globally or locally. Once you become familiar + with your driver's efuns, you can display those values in many different + ways. In addition, through the LPC operators, you know how to change + and evaluate the values contained in variables. This is useful of course + in that it allows you to do something like count how many apples have + been picked from a tree, so that once all apples have been picked, no + players can pick more. Unfortunately, you do not know how to have + code executed in anything other than a linera fashion. In other words, + hold off on that apple until the next chapter, cause you do not know + how to check if the apples picked is equal to the number of apples in the + tree. You also do not know about the special function init() where you + give new commands to players. But you are almost ready to code a nice, + fairly complex area. + + 6.7 LPC operators + This section contains a detailed listing of the simpler LPC operators, + including what they do to the values they use (if anything) and the value + that they have. + + The operators described here are: + = + - * / % += -= *= /= %= + -- ++ == != > < >= <= ! && || + -> ? : + + Those operators are all described in a rather dry manner below, but it is best + to at least look at each one, since some may not behave *exactly* as + you think. But it should make a rather good reference guide. + + = assignment operator: + example: x = 5; + value: the value of the variable on the *left* after its function is done + explanation: It takes the value of any expression on the *right* and + assigns it to the variable on the *left*. Note that you must use + a single variable on the left, as you cannot assign values to + constants or complex expressions. + + + addition operator: + example: x + 7 + value: The sum of the value on the left and the value on the right + exaplanation: It takes the value of the expression on the right and + adds it to the value of the expression on the left. For values + of type int, this means the numerical sum. For strings, + it means that the value on the right is stuck onto the value on + the left ("ab" is the value of "a"+"b"). This operator does not + modify any of the original values (i.e. the variable x from + above retains its old value). + + - subtraction operator: + example: x - 7 + value: the value of the expression on the left reduced by the right + explanation: Same characteristics as addition, except it subtracts. + With strings: "a" is the value of "ab" - "b" + + * multiplication operator: + example: x*7 + value and explanation: same as with adding and subtracting except + this one performs the math of multiplication + + / division operator: + example: x/7 + value and explanation: see above + + += additive assignment operator: + example: x += 5 + value: the same as x + 5 + exaplanation: It takes the value of the variable on the left + and the value of the expression on the right, adds them together + and assigns the sum to the variable on the left. + example: if x = 2... x += 5 assigns the value + 7 to the variable x. The whole expression + has the value of 7. + + -= subtraction assignment operator + example: x-=7 + value: the value of the left value reduced by the right value + examplanation: The same as += except for subtraction. + + *= multiplicative assignment operator + example: x *= 7 + value: the value of the left value multiplied by the right + explanation: Similar to -= and += except for addition. + + /= division assignment operator + example: x /= 7 + value: the value of the variable on the left divided by the right value + explanation: similar to above, except with division + + ++ post/pre-increment operators + examples: i++ or ++i + values: + i++ has the value of i + ++i has the value of i+1 + explanation: ++ changes the value of i by increasing it by 1. + However, the value of the expression depends on where you + place the ++. ++i is the pre-increment operator. This means + that it performs the increment *before* giving a value. + i++ is the post-ncrement operator. It evalutes before incrementing + i. What is the point? Well, it does not much matter to you at + this point, but you should recognize what it means. + + -- post/pre-decrement operators + examples: i-- or --i + values: + i-- the value of i + --i the value of i reduced by 1 + explanation: like ++ except for subtraction + + == equality operator + example: x == 5 + value: true or false (not 0 or 0) + explanation: it does nothing to either value, but + it returns true if the 2 values are the same. + It returns false if they are not equal. + + != inequality operator + example: x != 5 + value: true or false + explanation returns true if the left expression is not equal to the right + expression. It returns fals if they are equal + + > greater than operator + example: x > 5 + value: true or false + explanation: true only if x has a value greater than 5 + false if the value is equal or less + + < less than operator + >= greater than or equal to operator + <= less than or equal to operator + examples: x < y x >= y x <= y + values: true or false + explanation: similar as to > except + < true if left is less than right + >= true if left is greater than *or equal to* right + <= true if the left is less than *or equal to* the right + + && logical and operator + || logical or operator + examples: x && y x || y + values: true or false + explanation: If the right value and left value are non-zero, && is true. + If either are false, then && is false. + For ||, only one of the values must be true for it to evaluate + as true. It is only false if both values indeed + are false + + ! negation operator + example: !x + value: true or false + explanation: If x is true, then !x is false + If x is false, !x is true. + + A pair of more complicated ones that are here just for the sake of being + here. Do not worry if they utterly confuse you. + + -> the call other operator + example: this_player()->GetKeyName() + value: The value returned by the function being called + explanation: It calls the function which is on the right in the object + on the left side of the operator. The left expression *must* be + an object, and the right expression *must* be the name of a function. + If not such function exists in the object, it will return 0 (or + more correctly, undefined). + + ? : conditional operator + example: x ? y : z + values: in the above example, if x is try, the value is y + if x is false, the value of the expression is z + explanation: If the leftmost value is true, it will give the expression as + a whole the value of the middle expression. Else, it will give the + expression as a whole the value of the rightmost expression. + + A note on equality: A very nasty error people make that is VERY difficult + to debug is the error of placing = where you mean ==. Since + operators return values, they both make sense when being evaluated. + In other words, no error occurs. But they have very different values. For example: + if(x == 5) if(x = 5) + The value of x == 5 is true if the value of x is 5, false othewise. + The value of x = 5 is 5 (and therefore always true). + The if statement is looking for the expression in () to be either true or false, + so if you had = and meant ==, you would end up with an expression that is + always true. And you would pull your hair out trying to figure out + why things were not happening like they should :) diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter7 ds2.1/lib/doc/lpc/basic/chapter7 *** ds1.1/lib/doc/lpc/basic/chapter7 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter7 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,432 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 10 july 1993 + + CHAPTER 7: Flow Control + + 7.1 Review of variables + Variables may be manipulated by assigning or changing values with the + expressions =, +=, -=, ++, --. Those expressions may be combined with + the expressions -, +, *, /, %. However, so far, you have only been + shown how to use a function to do these in a linear way. For example: + + int hello(int x) { + x--; + write("Hello, x is "+x+".\n"); + return x; + } + + is a function you should know how to write and understand. But what + if you wanted to write the value of x only if x = 1? Or what if + you wanted it to keep writing x over and over until x = 1 before + returning? LPC uses flow control in exactly the same way as C and C++. + + 7.2 The LPC flow control statements + LPC uses the following expressions: + + if(expression) instruction; + + if(expression) instruction; + else instruction; + + if(expression) instruction; + else if(expression) instruction; + else instruction; + + while(expression) instruction; + + do { instruction; } while(expression); + + switch(expression) { + case (expression): instruction; break; + default: instruction; + } + + Before we discuss these, first something on what is meant by expression and + instruction. An expression is anything with a value like a variable, + a comparison (like x>5, where if x is 6 or more, the value is 1, else the + value is 0), or an assignment(like x += 2). An instruction can be any + single line of lpc code like a function call, a value assignment or + modification, etc. + + You should know also the operators &&, ||, ==, !=, and !. These are the + logical operators. They return a nonzero value when true, and 0 when false. + Make note of the values of the following expressions: + + (1 && 1) value: 1 (1 and 1) + (1 && 0) value: 0 (1 and 0) + (1 || 0) value: 1 (1 or 0) + (1 == 1) value: 1 (1 is equal to 1) + (1 != 1) value: 0 (1 is not equal to 1) + (!1) value: 0 (not 1) + (!0) value: 1 (not 0) + + In expressions using &&, if the value of the first item being compared + is 0, the second is never tested even. When using ||, if the first is + true (1), then the second is not tested. + + 7.3 if() + The first expression to look at that alters flow control is if(). Take + a look at the following example: + + 1 void reset() { + 2 int x; + 3 + 4 ::reset(); + 5 x = random(10); + 6 if(x > 50) SetSearch_func("floorboards", "search_floor"); + 7 } + + The line numbers are for reference only. + In line 2, of course we declare a variable of type int called x. Line 3 + is aethetic whitespace to clearly show where the declarations end and the + function code begins. The variable x is only available to the function + reset(). + Line 4 makes a call to the room.c version of reset(). + Line 5 uses the driver efun random() to return a random number between + 0 and the parameter minus 1. So here we are looking for a number between + 0 and 99. + In line 6, we test the value of the expression (x>50) to see if it is true + or false. If it is true, then it makes a call to the room.c function + SetSearch_func(). If it is false, the call to SetSearch_func() is never + executed. + In line 7, the function returns driver control to the calling function + (the driver itself in this case) without returning any value. + + If you had wanted to execute multiple instructions instead of just the one, + you would have done it in the following manner: + + if(x>50) { + SetSearch_func("floorboards", "search_floor"); + if(!present("beggar", this_object())) make_beggar(); + } + + Notice the {} encapsulate the instructions to be executed if the test + expression is true. In the example, again we call the room.c function + which sets a function (search_floor()) that you will later define yourself + to be called when the player types "search floorboards" (NOTE: This is + highly mudlib dependent. Nightmare mudlibs have this function call. + Others may have something similar, while others may not have this feature + under any name). Next, there is another if() expression that tests the + truth of the expression (!present("beggar",this_object())). The ! in the + test expression changes the truth of the expression which follows it. In + this case, it changes the truth of the efun present(), which will return + the object that is a beggar if it is in the room (this_object()), or it + will return 0 if there is no beggar in the room. So if there is a beggar + still living in the room, (present("beggar", this_object())) will have + a value equal to the beggar object (data type object), otherwise it will + be 0. The ! will change a 0 to a 1, or any nonzero value (like the + beggar object) to a 0. Therefore, the expression + (!present("beggar", this_object())) is true if there is no beggar in the + room, and false if there is. So, if there is no beggar in the room, + then it calls the function you define in your room code that makes a + new beggar and puts it in the room. (If there is a beggar in the room, + we do not want to add yet another one :)) + + Of course, if()'s often comes with ands or buts :). In LPC, the formal + reading of the if() statement is: + + if(expression) { set of intructions } + else if(expression) { set of instructions } + else { set of instructions } + + This means: + + If expression is true, then do these instructions. + Otherise, if this second expression is true, do this second set. + And if none of those were true, then do this last set. + + You can have if() alone: + + if(x>5) write("Foo,\n"); + + with an else if(): + + if(x > 5) write("X is greater than 5.\n"); + else if(x >2) write("X is less than 6, but greater than 2.\n"); + + with an else: + + if(x>5) write("X is greater than 5.\n"); + else write("X is less than 6.\n"); + + or the whole lot of them as listed above. You can have any number of + else if()'s in the expression, but you must have one and only one + if() and at most one else. Of course, as with the beggar example, + you may nest if() statements inside if() instructions. (For example, + if(x>5) { + if(x==7) write("Lucky number!\n"); + else write("Roll again.\n"); + } + else write("You lose.\n"); + + 7.4 The statements: while() and do {} while() + Prototype: + while(expression) { set of instructions } + do { set of instructions } while(expression); + + These allow you to create a set of instructions which continue to + execute so long as some expression is true. Suppose you wanted to + set a variable equal to a player's level and keep subtracting random + amounts of either money or hp from a player until that variable equals + 0 (so that player's of higher levels would lose more). You might do it + this way: + + 1 int x; + 2 + 3 x = (int)this_player()->query_level(); /* this has yet to be explained */ + 4 while(x > 0) { + 5 if(random(2)) this_player()->add_money("silver", -random(50)); + 6 else this_player()->add_hp(-(random(10)); + 7 x--; + 8 } + + The expression this_player()->query_level() calIn line 4, we start a loop that executes so long as x is greater than 0. + Another way we could have done this line would be: + while(x) { + The problem with that would be if we later made a change to the funtion + y anywhere between 0 and 49 coins. + In line 6, if instead it returns 0, we call the add_hp() function in the + player which reduces the player's hit points anywhere between 0 and 9 hp. + In line 7, we reduce x by 1. + At line 8, the execution comes to the end of the while() instructions and + goes back up to line 4 to see if x is still greater than 0. This + loop will keep executing until x is finally less than 1. + + You might, however, want to test an expression *after* you execute some + instructions. For instance, in the above, if you wanted to execute + the instructions at least once for everyone, even if their level is + below the test level: + + int x; + + x = (int)this_player()->query_level(); + do { + if(random(2)) this_player()->add_money("silver", -random(50)); + else this_player()->add_hp(-random(10)); + x--; + } while(x > 0); + + This is a rather bizarre example, being as few muds have level 0 players. + And even still, you could have done it using the original loop with + a different test. Nevertheless, it is intended to show how a do{} while() + works. As you see, instead of initiating the test at the beginning of the + loop (which would immediately exclude some values of x), it tests after + the loop has been executed. This assures that the instructions of the loop + get executed at least one time, no matter what x is. + + 7.5 for() loops + Prototype: + for(initialize values ; test expression ; instruction) { instructions } + + initialize values: + This allows you to set starting values of variables which will be used + in the loop. This part is optional. + + test expression: + Same as the expression in if() and while(). The loop is executed + as long as this expression (or expressions) is true. You must have a + test expression. + + instruction: + An expression (or expressions) which is to be executed at the end of each + loop. This is optional. + + Note: + for(;expression;) {} + IS EXACTLY THE SAME AS + while(expression) {} + + Example: + + 1 int x; + 2 + 3 for(x= (int)this_player()->query_level(); x>0; x--) { + 4 if(random(2)) this_player()->add_money("silver", -random(50)); + 5 else this_player()->add_hp(-random(10)); + 6 } + + This for() loop behaves EXACTLY like the while() example. + Additionally, if you wanted to initialize 2 variables: + + for(x=0, y=random(20); x<y; x++) { write(x+"\n"); } + + Here, we initialize 2 variables, x and y, and we separate them by a + comma. You can do the same with any of the 3 parts of the for() + expression. + + 7.6 The statement: switch() + Prototype: + switch(expression) { + case constant: instructions + case constant: instructions + ... + case constant: instructions + default: instructions + } + + This is functionally much like if() expressions, and much nicer to the + CPU, however most rarely used because it looks so damn complicated. + But it is not. + + First off, the expression is not a test. The cases are tests. A English + sounding way to read: + + 1 int x; + 2 + 3 x = random(5); + 4 switch(x) { + 5 case 1: write("X is 1.\n"); + 6 case 2: x++; + 7 default: x--; + 8 } + 9 write(x+"\n"); + + is: + + set variable x to a random number between 0 and 4. + In case 1 of variable x write its value add 1 to it and subtract 1. + In case 2 of variable x, add 1 to its value and then subtract 1. + In other cases subtract 1. + Write the value of x. + + switch(x) basically tells the driver that the variable x is the value + we are trying to match to a case. + Once the driver finds a case which matches, that case *and all following + cases* will be acted upon. You may break out of the switch statement + as well as any other flow control statement with a break instruction in + order only to execute a single case. But that will be explained later. + The default statement is one that will be executed for any value of + x so long as the switch() flow has not been broken. You may use any + data type in a switch statement: + + string name; + + name = (string)this_player()->GetKeyName(); + switch(name) { + case "descartes": write("You borg.\n"); + case "flamme": + case "forlock": + case "shadowwolf": write("You are a Nightmare head arch.\n"); + default: write("You exist.\n"); + } + + For me, I would see: + You borg. + You are a Nightmare head arch. + You exist. + + Flamme, Forlock, or Shadowwolf would see: + You are a Nightmare head arch. + You exist. + + Everyone else would see: + You exist. + + 7.7 Altering the flow of functions and flow control statements + The following instructions: + return continue break + + alter the natural flow of things as described above. + First of all, + return + no matter where it occurs in a function, will cease the execution of that + function and return control to the function which called the one the + return statement is in. If the function is NOT of type void, then a + value must follow the return statement, and that value must be of a + type matching the function. An absolute value function would look + like this: + + int absolute_value(int x) { + if(x>-1) return x; + else return -x; + } + + In the second line, the function ceases execution and returns to the calling + function because the desired value has been found if x is a positive + number. + + continue is most often used in for() and while statements. It serves + to stop the execution of the current loop and send the execution back + to the beginning of the loop. For instance, say you wanted to avoid + division by 0: + + x= 4; + while( x > -5) { + x-- + if(!x) continue; + write((100/x)+"\n"); + } + write("Done.\n") + + You would see the following output: + 33 + 50 + 100 + -100 + -50 + -33 + -25 + Done. + To avoid an error, it checks in each loop to make sure x is not 0. + If x is zero, then it starts back with the test expression without + finishing its current loop. + + In a for() expression + for(x=3; x>-5; x--) { + if(!x) continue; + write((100/x)+"\n"); + } + write("Done.\n"); + It works much the same way. Note this gives exactly the same output + as before. At x=1, it tests to see if x is zero, it is not, so it + writes 100/x, then goes back to the top, subtracts one from x, checks to + see if it is zero again, and it is zero, so it goes back to the top + and subtracts 1 again. + + break + This one ceases the function of a flow control statement. No matter + where you are in the statement, the control of the program will go + to the end of the loop. So, if in the above examples, we had + used break instead of continue, the output would have looked like this: + + 33 + 50 + 100 + Done. + + continue is most often used with the for() and while() statements. + break however is mostly used with switch() + + switch(name) { + case "descartes": write("You are borg.\n"); break; + case "flamme": write("You are flamme.\n"); break; + case "forlock": write("You are forlock.\n"); break; + case "shadowwolf": write("You are shadowwolf.\n"); break; + default: write("You will be assimilated.\n"); + } + + This functions just like: + + if(name == "descartes") write("You are borg.\n"); + else if(name == "flamme") write("You are flamme.\n"); + else if(name == "forlock") write("You are forlock.\n"); + else if(name == "shadowwolf") write("You are shadowwolf.\n"); + else write("You will be assimilated.\n"); + + except the switch statement is much better on the CPU. + If any of these are placed in nested statements, then they alter the + flow of the most immediate statement. + + 7.8 Chapter summary + This chapter covered one hell of a lot, but it was stuff that needed to + be seen all at once. You should now completely understand if() for() + while() do{} while() and switch(), as well as how to alter their flow + using return, continue, and break. Effeciency says if it can be done in + a natural way using switch() instead of a lot of if() else if()'s, then + by all means do it. You were also introduced to the idea of calling + functions in other objects. That however, is a topic to be detailed later. + You now should be completely at ease writing simple rooms (if you have + read your mudlib's room building document), simple monsters, and + other sorts of simple objects. diff -c -r --new-file ds1.1/lib/doc/lpc/basic/chapter8 ds2.1/lib/doc/lpc/basic/chapter8 *** ds1.1/lib/doc/lpc/basic/chapter8 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/basic/chapter8 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,195 ---- + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 12 july 1993 + + CHAPTER 8: The data type "object" + + 8.1 Review + You should now be able to do anything so long as you stick to calling + functions within your own object. You should also know, that at the + bare minimum you can get the create() (or reset()) function in your object + called to start just by loading it into memory, and that your reset() + function will be called every now and then so that you may write the + code necessary to refresh your room. Note that neither of these + functions MUST be in your object. The driver checks to see if the + function exists in your object first. If it does not, then it does not + bother. You are also acquainted with the data types void, int, and string. + + 7.2 Objects as data types + In this chapter you will be acquainted with a more complex data type, + object. An object variable points to a real object loaded into the + driver's memory. You declare it in the same manner as other data types: + object ob; + It differs in that you cannot use +, -, +=, -=, *, or / (what would it + mean to divide a monster by another monster?). And since efuns like + say() and write() only want strings or ints, you cannot write() or + say() them (again, what would it mean to say a monster?). + But you can use them with some other of the most important efuns on any + LPMud. + + 8.3 The efun: this_object() + This is an efun which returns an object in which the function being executed + exists. In other words, in a file, this_object() refers to the object your + file is in whether the file gets cloned itself or inherted by another file. + It is often useful when you are writing a file which is getting inherited + by another file. Say you are writing your own living.c which gets + inherited by user.c and monster.c, but never used alone. You want to log + the function set_level() it is a player's level being set (but you do not + care if it is a monster. + You might do this: + + void set_level(int x) { + if(this_object()->is_player()) log_file("levels", "foo\n"); + level = x; + } + + Since is_player() is not defined in living.c or anything it inherits, + just saying if(is_player()) will result in an error since the driver + does not find that function in your file or anything it inherits. + this_object() allows you to access functions which may or may not be + present in any final products because your file is inherited by others + without resulting in an error. + + 8.4 Calling functions in other objects + This of course introduces us to the most important characteristic of + the object data type. It allows us to access functions in other objects. + In previous examples you have been able to find out about a player's level, + reduce the money they have, and how much hp they have. + Calls to functions in other objects may be done in two ways: + + object->function(parameters) + call_other(object, "function", parameters); + + example: + this_player()->add_money("silver", -5); + call_other(this_player(), "add_money", "silver", -5); + + In some (very loose sense), the game is just a chain reaction of function + calls initiated by player commands. When a player initiates a chain of + function calls, that player is the object which is returned by + the efun this_player(). So, since this_player() can change depending + on who initiated the sequence of events, you want to be very careful + as to where you place calls to functions in this_player(). The most common + place you do this is through the last important lfun (we have mentioned + create() and reset()) init(). + + 8.5 The lfun: init() + Any time a living thing encounters an object (enters a new room, or enters + the same room as a certain other object), init() is called in all of + the objects the living being newly encounters. It is at this point + that you can add commands the player can issue in order to act. + Here is a sample init() function in a flower. + + void init() { + ::init(); + add_action("smell_flower", "smell"); + } + + Ito smell_flower(). So you should have smell_flower() look like this: + + 1 int smell_flower(string str); /* action functions are type int */ + 2 + 3 int smell_flower(string str) { + 4 if(str != "flower") return 0; /* it is not the flower being smelled */ + 5 write("You sniff the flower.\n"); + 6 say((string)this_player()->GetName()+" smells the flower.\n"); + 7 this_player()->add_hp(random(5)); + 8 return 1; + 9 } + + In line 1, we have our function declared. + In line 3, smell_flower() begins. str becomes whatever comes after the + players command (not including the first white space). + In line 4, it checks to see if the player had typed "smell flower". If + the player had typed "smell cheese", then str would be "cheese". If + it is not in fact "flower" which is being smelled, then 0 is returned, + letting the driver know that this was not the function which should + have been called. If in fact the player had a piece of cheese as well + which had a smell command to it, the driver would then call the function + for smelling in that object. The driver will keep calling all functions + tied to smell commands until one of them returns 1. If they all return + 0, then the player sees "What?" + In line 5, the efun write() is called. write() prints the string which + is passed to it to this_player(). So whoever typed the command here + sees "You sniff the flower." + In line 6, the efun say() is called. say() prints the string which is + doing the sniffing, we have to call the GetName() function + in this_player(). That way if the player is invis, it will say + "Someone" (or something like that), and it will also be properly + capitalized. + In line 7, we call the add_hp() function in the this_player() object, + since we want to do a little healing for the sniff (Note: do not + code this object on your mud, whoever balances your mud will shoot you). + In line 8, we return control of the game to the driver, returning 1 to + let it know that this was in fact the right function to call. + + 8.6 Adding objects to your rooms + And now, using the data type object, you can add monsters to your rooms: + + void create() { + ::create(); + SetProperty("light", 3); + set("short", "Krasna Square"); + set("long", "Welcome to the Central Square of the town of Praxis.\n"); + SetExits( ({ "/domains/standard/hall" }), ({ "east" }) ); + } + + void reset() { + object ob; + + ::reset(); + if(present("guard")) return; /* Do not want to add a guard if */ + ob = new("/std/monster"); /* one is already here */ + ob->SetKeyName("guard"); + ob->set("id", ({ "guard", "town guard" }) ); + ob->set("short", "Town guard"); + ob->set("long", "He guards Praxis from nothingness.\n"); + ob->SetGender("male"); + ob->set_race("human"); + ob->set_level(10); + ob->set_alignment(200); + ob->set_humanoid(); + ob->set_hp(150); + ob->set_wielding_limbs( ({ "right hand", "left hand" }) ); + ob->eventMove(this_object()); + } + + Now, this will be wildly different on most muds. Some, as noted before, + in that object so you have a uniquely configured monster object. The + last act in native muds is to call eventMove() in the monster object to move + it to this room (this_object()). In compat muds, you call the efun + move_object() which takes two parameters, the object to be moved, and the + object into which it is being moved. + + 8.7 Chapter summary + At this point, you now have enough knowledge to code some really nice + stuff. Of course, as I have been stressing all along, you really need + to read the documents on building for your mud, as they detail which + functions exist in which types of objects for you to call. No matter + what your knowledge of the mudlib is, you have enough know-how to + give a player extra things to do like sniffing flowers or glue or whatever. + At this point you should get busy coding stuff. But the moment things + even look to become tedious, that means it is time for you to move to + the next level and do more. Right now code yourself a small area. + Make extensive use of the special functions coded in your mud's + room.c (search the docs for obscure ones no one else seems to use). + Add lots o' neat actions. Create weapons which have magic powers which + gradually fade away. All of this you should be able to do now. Once + this becomes routine for you, it will be time to move on to intermediate + stuff. Note that few people actually get to the intermediate stuff. + If you have played at all, you notice there are few areas on the mud + which do what I just told you you should be able to do. It is not + because it is hard, but because there is a lot of arrogance out there + on the part of people who have gotten beyond this point, and very little + communicating of that knowledge. The trick is to push yourself and + think of something you want to do that is impossible. If you ask someone + in the know how to do X, and they say that is impossible, find out + youself how to code it by experimenting. + + George Reese + Descartes of Borg + 12 july 1993 + borg@hebron.connected.com + Descartes@Nightmare (intermud) + Descartes@Igor (not intermud) diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/MudOSdriver ds2.1/lib/doc/lpc/concepts/MudOSdriver *** ds1.1/lib/doc/lpc/concepts/MudOSdriver Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/MudOSdriver Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,32 ---- + What is the MudOS driver? + + The MudOS driver is the program (written in C) which + provides the lowlevel support that makes a mud possible. The driver + does many things including: + + <DL> + * accepts connections from remote machines (via a communications port) and + attaches those connections to the login object (/adm/login.c on TMI). + + * provides a set of external functions (efuns) that may be called from + within LPC objects. + + * compiles files into a compact internal tokenized form via the new(filename) + (or clone_object(filename)) efun. + + * interprets (executes) objects represented in the tokenized form. The + two main ways in which code gets executed are as follows: + + <UL> + <LI> a) the driver calls functions in objects based on input received from + users (via the communications port). The specific functions that get + called depend on what associations the objects of the mud have specified + between player-typed commands and functions (via the + add_action(function_name,command_name) efun). The driver also + calls functions in LPC objects from within certain efuns (such as "init", + "create", "clean_up", etc.). + <LI> b) objects can cause the driver to execute code in other objects via + the call_other(object,function_name,args,...) efun. An alternate + form of the call_other efun is object->function_name(args,...). + </UL> + </DT> diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/defines ds2.1/lib/doc/lpc/concepts/defines *** ds1.1/lib/doc/lpc/concepts/defines Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/defines Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,26 ---- + Predefined preprocessor #defines + + Note: additional predefines may be added from the command line using the -D + flag. Also, anything defined in either options.h will be available surrounded + by __; e.g if FOO is defined in options.h, the __FOO__ will be defined in all + objects. + + The following identifiers may be defined: + + <DL> + * MUDOS: always defined + * "2.7.2": a string representing the version of MudOS being run + * __PORT__: archaic; the port number of the first (previously, the only) external port + * __ARCH__: the name of the architecture of the machine + * __COMPILER__: the compiler MudOS was compiled with + * __OPTIMIZATION__: the optimization used + * MUD_NAME: the MUD name from the config file + * HAS_ED: defined if the ed() efun is available + * HAS_PRINTF: defined if the printf() efun is available + * HAS_RUSAGE: defined if the rusage() efun is available + * HAS_DEBUG_LEVEL: defined if the debug_level() efun is available + * "doc/concepts/defines.c": the file being compiled + * __DIR__: the directory the file is in (with the trailing /) + </DL> + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/lpc ds2.1/lib/doc/lpc/concepts/lpc *** ds1.1/lib/doc/lpc/concepts/lpc Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/lpc Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,61 ---- + What is LPC? + + LPC is the language in which MudOS (and LPmud) objects are written. + LPC stands for Lars Pensj| C. As one might surmise from the name, + LPC is based on the syntax of C. LPC provides the C while loop, for loop, + if statement, switch statement, a variant of sscanf, and integer data type, + (LPC also provides other data types not in C such as the object and the + mapping). LPC uses C's syntax for defining and calling functions and for + declaring variables. Note that LPC's version of the string datatype is + much different from that provided by C. See the LPC tutorial on syntax + and language constructs for more information. + + Here are some differences between LPC and C: + + There is no need for a function named "main" in LPC objects (although there + is one called "create"). + + The efuns (or system calls) provided by the gamedriver are different than + those typically found in the C library (libc.a). + + There is no malloc(). However, there is an allocate(int value) efun that + lets space be allocated for arrays. Note that the argument to 'allocate' + is not in units of bytes, but rather in units of elements. + + Memory is never explicitly deallocated. The gamedriver keeps track of + how many times a given piece of data has been referenced. When the + reference count goes to zero (when no object has a copy of that variable), + then the space used by the variable is reclaimed (garbage collected). + + The string data type in LPC is closer to that provided by BASIC than that + provided by C. Strings are not declared as arrays of characters but rather + as a basic intrinsic type. Strings may be concatenated using the '+' operator. + + For example, the LPC statements: + + <pre> + string ack; + + ack = foo + bar; + </pre> + + are equivalent to the C statements: + + <pre> + char *ack; + + ack = (char *)malloc(strlen(foo) + 1); + strcpy(ack,foo); + ack = (char *)realloc(strlen(ack) + strlen(bar) + 1); + strcat(ack,bar); + </pre> + + LPC is an interpreted language (however it is compiled into an internal + compact tokenized form before being interpreted). + + sscanf does not work in the same way as in C. arguments to sscanf need not + be pointers (since LPC does not have the explicit pointer data type). Also, + sscanf(arg,"%s %s",str1,str2) does not operate as the C programmer would + expect. In C, the first word of arg would be copied into str1 and the + second word of arg into str2. In LPC, the first word is copied into str1 + and the _remainder_ of arg is copied into str2. diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/message_doc ds2.1/lib/doc/lpc/concepts/message_doc *** ds1.1/lib/doc/lpc/concepts/message_doc Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/message_doc Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,199 ---- + message + + message is a new efun in MudOS designed to make communication efuns more + generic and to provide a standard way of talking to clients intelligently. + + See the message() efun doc for details on how the efun works. + + Probably the most important element of this function is the "class". + If used properly, you could use this field to implement a very simple + version of earmuffs, or to communicate intelligently with a custom + client. The class defines the type of message that the string + contains. Initial simple implementations would have the classes + "shout", "say", "write", "tell_object" (which would be generated by + simul_efuns of the same name that replace the more traditional efuns). + + Given this, let's say that you wanted to implment a quick and easy + earmuff ability. (the ability to mask shouts) In your user (player) + object, you would have the function receive_message. Here's the + simplest implementation possible: + + <pre> + void receive_message (string msg, mixed class) + { + receive(msg); + } + </pre> + + This simply takes all messages generated by the message efun and + displays them to the user. However, you could imagine a simple + earmuffs implementation on top of this: + + <pre> + string *muffle = ({}); + + int muffle_class (string arg) + { + muffle += ({arg}); + } + + void receive_message (string msg, string class) + { + if (member_array(class,string) == -1) + receive(msg); + } + </pre> + + Now you can see, that if a particular class is muffled (say, "shout" + for example), the text never gets displayed, but in other cases it + does. + + However, not all uses of the shout() efun are really shouts, in the + traditional mud sense. For example, let's say that the admin of the + mud wants to send a message to all users telling them that the system + is going to be shut down in 5 minutes. To do this, they might use + echo, which in turn uses the shout() efun. So all users who had + "shout" muffled would miss this important message. This means that a + broader number of classes is really needed to make message() truly + useful. For the example given, let's say we make a new "broadcast" + class. This message class would be used for important announcements + that everyone should hear. Perhaps a restriction could even be made + so that muffle prohibited blocking this class. + + Let's look at another example. What if you're tired of all of the + millions of emotes (soul commands) that clutter your screen? Wouldn't + it be nice to just muffle those? Well, obviously a new "emote" class + is needed that all soul functions use. Now you might be thinking to + yourself "hey... I don't want to have to use this really complex + message() efun every time I write a soul command. write() and say() + are very simple, and I like using those." Well, I couldn't agree with + you more. To combat that problem, I make a simul_efun for each type + of commonly used message class. Like emote for example. I made a new + simul_efun called emote() that in fact made writing soul commands + easier, and used message() with the "emote" class. I won't show you + the code for the emote simul_efun, but here's the basic idea: + + <pre> + varargs int emote (object emoter, string self_message, string + other_message, mixed emotee, string target_message, string modifier); + + emoter - the object doing the emoting + self_message - the message displayed to the emoter + other_message - the message displayed to the whole room + emotee - the target of the emote (i.e. kick huthar) + target_message - the message displayed to the emotee + string modifier - any extra modifier to tack on to the end of the + emote string. (i.e. adverbs: smiles happily, cheerfully, etc.) - only + really complex soul commands need this (if they want to be able to + control multiple modifiers to a single soul command) + </pre> + + At this point, some might be thinking, "ok... so you can do very + powerful selective muffling, big deal. this seems like a lot of work + for nothing." Good point. Muffling was just a simple neat thing you + could do with message now. Most of the real advantages from message + will come a bit down the line when someone gets around to writing a + smart client program. Here's how that will work. + + Basically the idea is to separate all of the messages sent to a user + by the content. So you have a "combat" class, and a "stat" class, and + a "room_description" class, and a "help" class as some examples. + Before I get started, let's write a new version of receive_message(). + + <pre> + int has_smart_client; + + void receive_message (string msg, string class) + { + if (member_array(class,muffle) == -1) { + if (has_smart_client) + receive (class + " : " + msg); + else + receive (msg); + } + } + </pre> + + Ok. Let's look at what this does. If the user object has defined + has_smart_client to be > 0, then it prepends all messages with the + class name as well. So if you were to write a smart client that + parsed messages like that, you could make it redirect room + descriptions into one window, conversation into another, combat into + yet another area, etc. You could make a status line that always kept + your current room name (since it got passed as class "room_name" when + you enetered the room). You could make the heart_beat, pass a class + "status" message which gives a constant readout of your hit points in + your status line. All of this would be transparent to the end user. + It would just work. + + In addition, you could do a simply graphical client using the same + technique. The BSX graphical mud / client could easily be implemented + on top of MudOS using message(). Or you could pass around small + bitmaps rather than the polygon-based line drawings of BSX. The + possibilities are pretty wide open. + + There is at least one major flaw with this argument so far. Since + everyone has to implement this message protocol themselves, and since + nobody has written a smart client to take advantage of the protocol, + then when a client comes out, what's to guarantee that your mudlib + will even work with it? Well, that's actually most of the point to + this document. I'd like to outline a simple protocol that I hope + everyone will adopt, so that when a client finally comes out, it will + work with all mudlibs that adhere to this protocol. + + (Note: It's now several years later, and AFAIK noone uses this protocol. + AMCP also exists and is supported by some mudlibs, but the only client is + very minimal. -Beek) + + The protocol: + + all messages sent to the smart client are in the form + + "class:msg_length:msg" + + msg_len is the length of the msg string. This is put in so that the + client can always know when it has received the entire message, and + when one starts and ends. + + The following list of classes should be used and a client should be + able to parse and use any messages using these classes. + + <pre> + say use of the "say" command or its equivalent + shout use of the "shout" command or its equivalent + tell use of the "tell" command or its equivalent + emote a soul command or emote + broadcast a broadcast message to everyone on the mud + combat generic combat messages + combat_self combat messages generated by the user's own attack + combat_other combat messages generated by others + combat_* all other specific combat messages + room_description a long description of a room or location + room_name a short name for a room or location + inventory what you're carrying + item_description a long description of the item + status generic status messages + status_hp current hit points + status_sp current spell points + status_sobriety current state of drunkeness + status_* all other specific status messages + score generic score messages + score_exp experience points + score_money the amount of coins or other money + developer a broadcast message to all wizards/developers + class_fighter a message to all fighters + class_mage a message to all mages + class_thief a message to all thieves + class_priest a message to all priests + class_* a message to the class specified + race_human a message to all humans + race_elf a message to all elves + race_dwarf a message to all dwarves + race_* a message to the race specified + + *** optional classes to implement *** + bitmap a generic bitmap message + bitmap_* a specific type of bitmap + drawing a generic drawing message + drawing_* a specific type of drawing + </pre> diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/objects ds2.1/lib/doc/lpc/concepts/objects *** ds1.1/lib/doc/lpc/concepts/objects Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/objects Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,16 ---- + objects + + What is an object? + + An object consists of a collection of functions (also called 'methods') + and data (variables) on which the functions operate. The only way to + manipulate the data contained in an object is via one of the functions + defined by the object. + + Every single thing in a mud is an object. Rooms are objects. Weapons + are objects. Even your character is an object (a special kind of object + called "interactive" but still an object in most every respect). Each + object (except possibly virtual objects) in the mud is associated with + some file written in LPC (in the mud's directory structure) that describes + how the object is to interact with the gamedriver and the rest of the objects + in the mud. diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/oop ds2.1/lib/doc/lpc/concepts/oop *** ds1.1/lib/doc/lpc/concepts/oop Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/oop Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,30 ---- + OOP + + OOP stands for "Object-Oriented Programming" + + If you know how to code in C or Pascal or even one of the modern BASICs + (with procedures), then you already have many of the skills you will need + to program effectively in LPC. The main thing you need is a skill in + translating your ideas into a sequential flow of steps (that a computer + can perform). However, LPC is also an object-oriented language. + To effectively use LPC, you would benefit from a knowledge of OOP principles + and concepts. Following are some of the principles of object-oriented + programming (note that LPC doesn't necessarily provide mechanisms + supporting all of these principles): + + <DL> + * systems are modularized on the basis of their data structures. + * objects should be described as implementations of abstract data types. + * unused objects should be deallocated by the underlying language system, + without programmer intervention. + * every non-simple type is a module, and every high-level module is a type. + * a class may be defined as an extension or restriction of another. + * program entities should be allowed to refer to objects of more than + one class, and operations should be permitted to have different realizations + in different classes. + * it should be possible to declare a class as heir to more than one class, + and more than once to the same class. + </DL> + + [These seven principles were taken from the "Object-oriented Software + Construction" book by Bertrand Meyer] diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/preprocessor ds2.1/lib/doc/lpc/concepts/preprocessor *** ds1.1/lib/doc/lpc/concepts/preprocessor Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/preprocessor Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,307 ---- + LPC Preprocessor Manual + + The preprocessor is a front end to the LPC compiler that provides such + handy features as: + + <DL> + * sharing definitions and code (#include) + * macros (#define, #undef) + * conditional compilation (#if, #ifdef, #ifndef, #else, #elif, #endif) + * debugging (#echo) + * compiler specific (#pragma) + * text formatting short cuts (@, @@) + </DL> + + The first three are identical to C usage, so those already familiar with + C may want to just skim the last few sections of this document. + + Note: + For those directives that begin with '#' (such as #include), the + '#' symbol must start in the first column (of the line). + + Sharing Definitions and Code + + This facility is provided through the #include directive. + + Syntax 1: #include <file.h> + + Syntax 2: #include "file.h" + + Notes: + The '#include <file.h>' form looks for the file, 'file.h' in the + system's standard include directories. + (On TMI this is just '/include'.) + + The '#include "file.h"' form looks for the file, 'file.h' in the + same directory as the file that is including it. + + The #include statement is a way to textually include one file into another. + Putting a statement such as '#include "file.h"' in a file gives the same + effect as if the contents of file.h had been directly entered into the file + at the point where the #include statement occurred. Included files are + recompiled each time the object that include's them is recompiled. If the + included file contains variables or functions of the same name as variables + in the file doing the including, then a duplicate-name error will occur at + compile time (in the same way that the error would occur if you simply typed + in file.h rather than using #include). + + Macros + + Macro definitions are used to replace subsequent instances of a given + word with a different sequence of text. Reasons for doing so include + hiding implementation details, reducing the number of keystrokes, and + ease in changing constants. + + Syntax 1: #define identifier token_sequence + + Syntax 2: #define identifier(id_list) token_sequence + + Notes: + As a matter of convention, identifiers are usually capitalized to + emphasize their presence in the code, and defined close to the + start of program, or in a separate header file which you #include. + + The second case allows identifiers in the id_list to be substituted + back into the token_sequence. + + Example: + + <pre> + // Create a 40 cell array of integers and initialize each cell + // to its cell number times 2, + // i.e. stack[0] = 0, stack[1] = 2, stack[2] = 4, etc + + #define STACKSIZE 40 + #define INITCELL(x) 2*x + + int *stack; + + create() { + int i; + + stack = allocate(STACKSIZE); + + for (i = 0; i < STACKSIZE; i++) + stack[i] = INITCELL(i); + } + </pre> + + Lastly, it's sometimes useful to undefine (i.e. make the compiler forget + about) a macro. The following directive is then used: + + Syntax: #undef identifier + + Note: + It's perfectly acceptable to undefine an identifier that hasn't been + defined yet. + + Conditional Compilation + + These directives can add flexibility to your code. Based on whether an + identifier is defined (or not defined), variations of the code can be + produced for different effects. Applications include selective admin + logging and support for multiple drivers (or versions of the same driver). + + <pre> + Syntax: #ifdef <identifier> + #ifndef <identifier> + #if <expression> + #elif <expression> + #else + #endif + </pre> + + Note: + <identifier> refers to an identifier that has been (or could be) defined + by your program, a file you have included, or a symbol predefined by + the driver. + + <expression> is a constant expression that evaluates to a boolean + condition. The expression may contain any legal combination of the + following: + </pre> + operators: ||, &&, >>, <<, + +, -, *, /, %, + &, |, ^, !, ~, + ==, !=, <, >, <=, >=, ?: + </pre> + parentheses for grouping: (, ) + calls of the form: defined(identifier) + and identifiers + + #ifdef identifier + can be considered shorthand for: + #if defined(identifier) + + #ifndef identifier + can be considered shorthand for: + #if !defined(identifier) + + #elif expression + can be considered shorthand for the sequence: + #else + # if expression + # endif + + Example 1: + + <pre> + // Using #if 0 allows you to comment out a block of code that + // contains comments. One reason to do so may be to keep a copy + // of the old code around in case the new code doesn't work. + #if 0 + // In this case, the constant expression evaluates + // (or is) 0, so the code here is not compiled + + write(user_name + " has " + total_coins + " coins\n"); + #else + // This is the alternate case (non-zero), so the code + // here _is_ compiled + + printf("%s has %d coins\n", user_name, total_coins); + #endif + </pre> + + Example 2: + + </pre> + // This example is derived from TMI's /adm/simul_efun/system.c + #ifdef __VERSION + string version() { return "2.7.2"; } + #elif defined(MUDOS_VERSION) + string version() { return MUDOS_VERSION; } + #else + # if defined(VERSION) + string version() { return VERSION; } + # else + string version() { return -1; } + # endif + #endif + </pre> + + Debugging + + The '#echo' directive allows you to print messages to the driver's stderr + (STanDard ERRor) stream. This facility is useful for diagnostics and + debugging. + + Syntax: #echo This is a message + + Note: + The rest of the line (or end-of-file, which ever comes first) is the + message, and is printed verbatim. It's not necessary to enclose text + with quotes. + + Compiler Specific + + This facility performs implementation-dependent actions. + + Syntax: #pragma keyword + + At this time the following control keywords are recognized: + + <DL> + * strict_types + * save_binary + * save_types + * warnings + * optimize + * show_error_context + </DL> + + Notes: + 'strict_types' informs the compiler that extensive type checking should + be done + + 'save_binary' informs the compiler to save the binary object; + loading will go faster after a reboot/shutdown since object has been + precompiled + + 'save_types' is saves the types of function arguments for type checking + in objects that inherit this program + + 'warnings' enables the printing of warnings about things the driver thinks + are dangerous or likely to be incorrect. + + 'optimize' directs the compiler to spend a little extra time generating + better code + + 'show_error_context' adds information about where on the line an error + occured to error messages + + Text Formatting Shortcuts + + This facility makes it easier to format text for help messages, room + descriptions, etc. + + <pre> + Syntax 1: @marker + <... text block ...> + marker + </pre> + + <pre> + Syntax 2: @@marker + <... text block ...> + marker + </pre> + + Notes: + <pre> + @ - produces a string suitable for write() + + @@ - produces an array of strings, suitable for the body pager + </pre> + + These are used by prepending '@' (or '@@') before an end marker word. This + is followed by your formatted text, as you would have it appear to the user. + The text block is terminated by the end marker word, without the '@' + (or '@@'). With '@', the text block is processed as if it were a single + string surrounded by quotes and '\n' (newlines) in between the lines. + With '@@', the text block is processed as it were an array of strings, + with each line being a string surrounded by quotes. + + <pre> + Example 1: + + int help() { + write( @ENDHELP + This is the help text. + It's hopelessly inadequate. + ENDHELP + ); + return 1; + } + + </pre> + Is equivalent to: + + <pre> + int help() { + write( "This is the help text\nIt's hopelessly inadequate.\n" ); + return 1; + } + </pre> + + Example 2: + + <pre> + int help() { + this_player()->more( @@ENDHELP + This is the help text. + It's hopelessly inadequate. + ENDHELP + , 1); + return 1; + } + </pre> + + Is equivalent to: + + <pre> + int help() { + this_player()->more( ({ "This is the help text.", + "It's hopelessly inadequate." }), 1); + return 1; + } + </pre> diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/simul_efun ds2.1/lib/doc/lpc/concepts/simul_efun *** ds1.1/lib/doc/lpc/concepts/simul_efun Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/simul_efun Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,28 ---- + Simulated efunctions + + There is a mechanism to allow the mudlib to simulate efunctions. All + simulated efuns must be defined in a special file (the name and location + of which are to be specified in the config file). + + When compiling an object and a function call (not a call_other) is found that + has not been defined in the object then the driver + will search for that function in the list of simulated efuns. If the + function is found in that list, then the driver sets up a call to + that function (as defined in the simulated efun file). + + Simulated efuns have many uses. One is that it is now possible to make major + changes (and even removals) to the behavior of efuns without modifying + the driver (by making a simul_efun having the same name as an efun). Suppose + you wish to modify the behavior of the move_object() efun. You could do + so by defining a simulated efun having the same name. The simulate efun + could perform various restrictive checks and then call efun::move_object(). + The efun:: prefix is necessary so that the driver will know you wish to call + the move_object efun and not recursively call the simulate_efun within which + the call to move_object is contained. [Note that valid_override() in master.c + can be used to conrol which simul_efuns may be overridden via the efun:: + prefix]. Simulated efuns are also useful for adding functions that many + different objects may need to call but which aren't appropriate for + inclusion in an inherited file. + + Any function in the simulated efun file that is declared static, will + not be callable by functions outside the simulated efun file. diff -c -r --new-file ds1.1/lib/doc/lpc/concepts/socket_efuns ds2.1/lib/doc/lpc/concepts/socket_efuns *** ds1.1/lib/doc/lpc/concepts/socket_efuns Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/concepts/socket_efuns Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,804 ---- + MudOS LPC Sockets Tutorial + 1992 October 20 + by Cynosure (Dave Richards) + + Minor update 1994 Sept 16 by Robocoder (Anthon Pang) + + Note: It is now possible to pass a function pointer anywhere a string + function name is mentioned in the following. + + One of the enhancements added to MudOS between 0.8.14 and 0.9.0 was the + inclusion of Internet sockets in LPC. It has been an ongoing dream of + the MudOS and TMI researchers to provide more tightly integrated MUDs + communicating over the Internet. Socket efuns (or LPC sockets) provide + the first level of MUD integration by allowing LPC developers to write + Internet sockets-based applications. For example, LPC objects already + exist for telnet, remote MUD finger, remote MUD tell, inter-MUD mail + delivery, and participation in the MUDWHO system. + + This document is intended as a tutorial on how to use LPC sockets to + write network-based intercommunicating objects. It is intended for + intermediate to advanced LPC programmers, who already understand the + fundementals of LPC programming, and wish to write network-based LPC + services. + + Socket Modes + + There are five different modes of communication, or socket modes: + MUD, STREAM, DATAGRAM, STREAM_BINARY, and DATAGRAM_BINARY. Definitions + for these modes can be obtained by including "socket.h" from the mudlib. + + MUD Mode + + MUD mode is a connection-oriented communication mode where LPC data types + may be passed across the network to another MUD. For example, in MUD mode + one could send structured data, like arrays or mappings, across the network + to another MUD which is using a MUD mode socket. All LPC data types _except_ + "objects" and "functions" may be sent and received using MUD mode. + + STREAM Mode + + STREAM mode is also a connection-oriented communication mode. It differs from + MUD mode however, in that all data is sent and received as strings. So, + using STREAM mode one can send streams of data across the network to other + MUDs. STREAM mode sockets are less powerful in that they do not + transparently send and receive all LPC data types. However, many + applications like telnet, for example, do not need to send data as + integers, or arrays. Instead, telnet views data as a stream of characters + going in each direction. + + MUD mode sockets are effectively implemented as STREAM mode sockets with + special code to send and receive LPC data types. Therefore, it behooves + one to only use MUD mode if the application requires this extra data + abstraction. MUD mode is inherently slower and uses more memory buffer + space than STREAM mode. Note that when using STREAM mode, there is + no guarantee that the string being sent will arrive all at once; + instead, it may arrive in pieces which the receiving side may then have + to reassemble (the pieces will arrive in order). + + DATAGRAM Mode + + Unlike MUD and STREAM modes, DATAGRAM mode is connectionless. No connection + is established between MUDs to transfer data. Instead, each piece of data + is sent to the destination MUD in a message called a datagram. + + Because no connection is estsblished in DATAGRAM mode, it is possible that + the network could lose the DATAGRAM and neither MUD would realize it! For + example, if TMI sent a datagram to Portals using DATAGRAM mode and the network + lost the datagram, Portals would never receive the datagram and would be + ignorant of the datagram ever being sent at all. And TMI won't realize the + datagram was lost because no error is received if the datagram is lost. + + TCP and UDP + + In MUD and STREAM mode, a TCP connection is established between the two MUDs. + TCP is a protocol that will re-transmit data if it detects that data has been + lost. It uses algorithms that send data, measure how long it takes to get a + reply, wait that long and re-transmit the data until an acknowledgement is + received. TCP also guarantees that the data packets arrive in order and + are not spuriously duplicated. (This is a very superficial description of + TCP, but does indicate the sort of work involved in making data transfer + reliable). + + DATAGRAM sockets, on the other hand, use a datagram oriented protocol called + UDP. UDPs send datagrams between MUDs without the overhead of connections, + retransmission, etc. Now, since DATAGRAM mode is unreliable why would one + want to use it? Clearly TCP is better because it guarantees that data is + retransmitted if it doesn't arrive, and it deals with all the ugliness that + a network can throw at it. Simply stated, some applications really don't + care if all data arrives at the other end. Then why send it? Okay, okay. + This is a good question, but now is too soon to talk about it. Just take + it on faith that there is a need for DATAGRAM mode and we can fill in the + details a bit later. + + Creating Sockets + + Ok, so let's start off by creating a MUD mode socket. We can write an + object to do this: + + <pre> + #include "socket.h" + + void + create() + { + int s; + + s = socket_create(MUD, "close_callback"); + if (s < 0) { + write("socket_create: " + socket_error(s) + "\n"); + return; + } + + write("Created socket descriptor " + s + "\n"); + + socket_close(s); + } + + void + close_callback(int s) + { + write("socket " + s + " has closed\n"); + } + </pre> + + Let's analyze this object to see how a socket is created. Be forewarned, + we have a long way to go before we can send data on a socket, and creation is + only one step along this trail. So be patient and be sure to understand + each example before moving. + + The first thing we do is #include "socket.h". All socket definitions + are contained in socket.h, remember? #defines exist, for example, for + MUD, STREAM and DATAGRAM. Although each name maps to a number, a well + written application will use this name instead; partly because the + you mean to do. + + We declare an integer variable s. In many sockets applocations s is used + as an abbreviation for socket. Then we call socket_create() with two + arguments. The first argument is the socket mode (which we discussed above), + and note that we use the synbolic name MUD for MUD mode. The second argument + in the above example is called the close callback function. It is the name + of a function within the object that MudOS will call when the connection is + closed. Callbacks are used often in LPC sockets efuns to notify the + object when important network events occur. Note, by the way, that we could + have passed STREAM or DATAGRAM to socket_create() to create STREAM or + DATAGRAM sockets. + + All socket efuns return an exit status or return value. This value indicates + the completion status of the function. By convention all values less than 0 + indicate errors or warnings. When an error is returned the application must + decide how to respond to it. In many cases there is no possibility for + success unless the MUD administrator makes changes to local config file or + the MudOS driver itself, so in many cases the application may decide to + just return on failure. In the above example, if an error is returned + (s is less than 0) then we use the socket efun socket_error() to write + an error message on the screen. This is useful during debegging, but should + probably be converted to log_file() calls eventually so the errors can be + logged and fixed. + + If socket_create() succeeds, it returns an integer greater than or equal to + 0. This integer is known as a socket, a socket descriptor or a file + descriptor. All three names have their origins in UNIX terminology. If + socket_create() returns a value less than 0 then an error has occurred and + no socket has been created. There really aren't any good reasons for + getting an error. The most common errors would be specifiying an incorrect + socket mode (which should not happen if you use the socket mode definitions + in socket.h) and out of sockets. The MUD administrator can configure the + number of LPC sockets that can be used by MudOS. By default, this number + is 16, but should be changed to fit the MUD's requirements. Increasing this + number will make more LPC sockets available. Note, that each active LPC + socket takes away one socket that could be used to handle a player login + or an open file. If the mud needs to handle many players and many open + sockets simultaneously, the machine adminstrator may need to be convinced + to increase the maximum number of open file descriptors allowed to a process. + + All socket objects should be careful not to "lose" sockets. Sockets + are not like other LPC objects, there are only a finite number of them. + So in the above example, if we were able to create a socket, we close it + afterwards. Losing track of a researce is called "leaking". Socket + leaks occur when object create sockets, use them for a while and then + stop using them without closing them so that they can be used by other + objects. When an object is destructed, all LPC sockets are automatically + closed. One other thought about sockets: each socket in MudOS has it's own + unique socket descriptor (or socket number). So if one object created a + socket, and another created a second socket, neither object would receive + the same socket descriptor. Object may use this knowledge to their advantage. + It is common, for example, to use the socket descriptor as an index into + a mapping that notes various information for each open socket. Remember, + however, that once the socket is closed, it becomes available for re-use + by other socket_create() calls. + + Client/Server Model + + Before continuing with the rest of the socket efuns now is probably a good + time to stop and review some basic networking concepts. Connection-oriented + communication is normally described in terms of the client/server model. In + this model each connection has a client and a server. The client is the + subject that initiates the connection and solicits some sort of service. + The server on the other hand waits for connection requests from a client, + and when they arrive provides the service requested. Ftp, for example, + operates this way. A user initiates a request by connecting to a server. + The server than acts on the requests of the client. A server + is unlike a client however in that is may be serving more than one client + at any point in time. + + MUD and STREAM mode sockets use the client/server model. The client and + server each using slightly different calls to establish a connection. + Later we will discuss the peer-to-peer model when discussing DATAGRAMS, + which is slightly different than the client/server model and uses an + again slightly different method for establishing communication. + + It is possible to have many different services available. Each service is + identified by a "well-known port". A port is simply an integer in the + range 1 to 65535. Most MUDs, however, can only use the range 1025 to + 65535 because the first 1023 are reserved for applications like telnet, + ftp, etc that are standardized. In order for a client and server to + cummunicate the server my first create a socket, bind to a well-known port + and listen for connection requests. The client on the other hand must + create a socket and connect to the well-known port. The client connects + to the same port as the server has bound and listened on. That is why + it is called a "well-known" port. Because clients know the port a priori + and can therefore connect to it. In the Internet Request for Comments + documentation, for example, the port number is actually specified with + the text of the standard. + + We will continue our discussion then in the order that socket efun + calls would normally be executed to establish a connection between the + client and server. The server must do some preperation before the + client can initiate a request, so we will start with the server. + + Binding to a Port + + After the server has created a socket with socket_create() (and has verified + that the return value is greater than or equal to 0) the next logical step + is to bind to a port. This is done with socket_bind(). Let's add some more + code to the example above. First let's declare a new integer variable + called error, which is used to hold the return value from socket_bind(). + + <pre> + int error; + + // Now let's add a call to socket_bind(): + + error = socket_bind(s, 12345); + if (error != EESUCCESS) { + write("socket_bind: " + socket_error(error) + "\n"); + socket_close(s); + return; + } + </pre> + + This should be added above socket_close(s). What does it do? Well + the first argument is no suprise, it's just the socket descriptor we + got back from socket_create(). We will have to pass s into every socket + call from now on so that MudOS knows which socket we are referring to. + Remember servers can and often do service more than one client socket at + one time, so we need to be able to keep them straight. The second argument is + simply the port number. Recall, it should be in the range 1024 to 65535. + (Actually 0 is legal too, but 0 will be discussed a bit later.) + + After calling socket_bind() we check the return value to see if an error + occurred. In this case, however, we compare against EESUCCESS. In most + cases (excluding socket_create()) EESUCCESS indicates that the socket efun + completed successfully. Like socket_create() above, if an error is returned + we call socket_error() to display the error as a string. After writing the + error we simply return, right? Wrong! We discussed leaks above. If we + were to return, then an object would exist that is no longer using a socket + but stops others from using it. If we decided we cannot use the socket + anymore CLOSE IT so others can. Once socket_create() has been called and + until socket_close() has been called the socket remains open. So remember + to be a good socket citizen and close sockets when you are finished. + + socket_bind() is notorious for returning EEADDRINUSE. What does it mean? + If one socket binds to port 12345 and another socket attempts to bind to the + same port (i.e. 12345) the second socket will fail to bind. This is simple + enough to understand. Once a socket binds to a port that socket owns that + port. Other attempts to bind to the same port will fail with EEADDRINUSE. + This is a very common error and can occur if two folks attempt to run the + same server demo, for example. The correct resolution to this problem is + to 1) determine if the same service is being started twice, in which case, + DON'T, once is fine, or 2) more than one developer has chosen the same + port number for multiple services. This won't work. One way to avoid this + is to have one port administrator that assign ports. Unfortunately, since + networks are generally not isolated, this port assignment must be agreed + upon by all MUDs that you intend to communicate with. + + Security + + Before going on and to satiate those with crimical intent we should answer + a few questions about invalid sockets descriptors. What happens if we were + to pass in a bad socket descriptor value, just to be mean? Don't worry MudOS + will catch you doing it and tell you so. For example, if you passed in + a value that was less then 0 or greater or equal to the total number of + possible sockets in the driver, then MudOS would know you were lying though + your teeth and would return EEFDRANGE. Now if you were more sneaky you + might try to pass in a legal socket descriptor but one that was not + currently is use. MudOS would catch you again and would return EBADF. Ok + sneak that you are, you found out about a socket that in use by some other + object. What then? Well there is a 2-level security system built into + LPC sockets. + + The first level of security uses the master object to validate which + objects can and cannot use sockets. It might make sense on some MUDs, for + example, for some developers to have access to LPC sockets and some others + not too. Or perhaps one developer is abusive of network priviledges and + should be banned from socket use. (In the latter case such a developer + should probably asked to leave.) To enforce such a policy, MudOS invokes + a function called valid_socket(). valid_socket() should return 0 or 1 + indicating whether the requested socket operation should be allowed. + If no valid_socket() function exists, then the value 0 is assumed and all + LPC socket access is *denied*. On most MUDs however master.c would + contain the following valid_socket(). + + <pre> + int + valid_socket(object eff_user, string fun, mixed *info) + { + return 1; + } + </pre> + + The 2nd level of security is more rigid and is used to stop one + object from interfering with another object. When a socket is created + the socket becomes "owned" by the object that called socket_create(). + Each time a socket efun is called the calling object is compared to the + owner object. If they are not the same, then the socket efun call is + aborted. Thus, heinous code like: + + <pre> + int s; + + for (s = 0; s < 100; s++) + socket_close(s); + </pre> + + will not succeed in closing all sockets on the MUD. It will close all + sockets owned by that calling object, but all other sockets are + protected by tge 2nd-level security policy. + + In either case if the 1st or 2nd level security policy is violated, then + EESECURITY is returned to the caller indicating that the socket efun was + aborted because of such a violation. If you encounter this error when + writing LPC socket code the mostly like reason would be that you passed in + the incorrect socket descriptor. This happens. + + Listening for Connections + + Once a socket has been created and a port has been bound, a server must + begin listening for connections. This is done with socket_listen(). + Like socket_bind() the first argument is the socket on which to listen. + The second argument is the "listen callback" function. Recall the + close callback function from socket_create()? socket_listen() specifies + a function within the object that will be called when a connection + request is received from a client. Within the listen callback function + a server can either accept the connection from the client or close it. + In most servers there is really no good reason for ever just closing a + connection. It is considered rude and should be avoided. If the + client and server implement some sort of authentication protocol + (i.e. password checking) the server should return some indication as + to why the socket is being closed. This is more a question of style, + of course, but it is difficult to debug a problem with a client or server + when a connection is made then dropped immediately. If you must do this, + be sure to log some indication as to why in a logfile so that an administrator + or developers can determine the cause and resolve the problem. + + The following code starts listening for connection requests on a socket + that has been created and bound to a port. + + <pre> + error = socket_listen(s, "listen_callback"); + if (error != EESUCCESS) { + write("socket_listen: " + socket_error(error) + "\n"); + socket_close(s); + return; + } + </pre> + + It is really just more of the same code, right? We call the socket_listen() + efun, check the return value for success, if an error occurs write an + error message out which includes a description of the specific error, + close the socket because we're done with it and return. In reality much + of the code necessary in sockets applications follow this pattern. + + Now obviously the next thing to do is discuss the listen_callback function, + right? Right. But we won't. Instead we'll change gears here and look at + the client code for a bit. The reason for this is simple. Before a client + can initiate a connection to a server the steps we have discussed now for + the server must have occured. Until the client *does* initiate a connection + though, no more code will be executed within the server. So it makes sense + to digress and discuss the client for a moment. + + Clients + + So far we have discussed a connection from the server's perspective. Now + let's back up and walk through the client. Just like the server a client + must call socket_create() to create a socket. Since a client does not + intend that another client connect to it there is no need to bind the + port to socket. Does this mean that it cannot do so? No. It is possible + for either a client or server to bind to a port. + + But why would a client wish to do so? Well the truth of the matter is this, + every socket must be bound before a connection can be established. Every one. + However, since clients don't really care what port they are bound to, a + special bind is used. It was alluded to above, we're just catching up to it + now. If a client calls socket_bind() with a second argument of 0, this + indicates that the caller doesn't care what port is selected, just pick + any one that is available. And this makes it easy for a client. If the + caller did bind to a specific port, what happens if another client is already + bound to it? The bind fails. So why not let the system do the work of + choosing the port? + + Now there is one more trick up our sleeve, however. The operating system + is pretty smart. It knows whether a sosket is bound or not. It knows when + you do a connect (It knows when you've been bad or good). So, seeing how + common it would be for a client to wish to connect to a server the designers + of the 4.2/4.3BSD networking system put in a neat feature. If you connect + on a socket, and the socket is not yet bound, the system will do a + socket_bind(s, 0) for you automatically! In fact if you read BSD networking + applications you will notice that almost no sockets that are used to + initiate connect requests on ever bother doing the bind call. Laziness is + bliss. + + Initiating a Connect + + Once a client has created a socket with socket_create() and optionally + bound to a port with socket_bind(), can then called socket_connect() to + initiate a connection request. socket_connect() requires four parameter: + 1. the socket on which the connection to be performed, 2. the address and + port to connection to, 3. the read callback function, and 4. the write callback + function. There are several new concepts we need to cover so let's go + slowly and review each argument in tern. + + The first argument is old hat by now. It is just the socket or (socket + descriptor) that was returned from socket_create(). The second argument, + however, is new and exciting. It is a string representating of the address + and port to which we want to connect. Rather than waste your time talking + about Internet standard dot notation, and address classes, etc, lets just + say this about Internet (or IP) addresses. You have probably seem them + before. They are 4-byte addresses, with each byte being separated by a ".". + For example, the Internet address for eng3.sequent.com is 138.96.19.14. + There are many ways to find the IP address for a machine. The mud list + supplies the host name and IP address for the MUD machine (which do change + from time to time). The UNIX ping and nslookup commands can be used, as well. + From this point on, we will just assume you can determine the IP address + for a destination machine. One thing to think about though is that in + general most applications to not embed IP addresses within the code. It is + more common that the user would provide tha address as an argument to the + application, so don't panic. + + We discussed ports above when we talked about binding. The port that + you specify to socket_connect() is the same "well-known" port number that + the server bound to above. That's the whole point, by the way, of binding. + The server and client rendezvous so to speak at the port. So how should + the second argument appear? Let's assume we wanted to connect to + eng3.sequent.com port 12345. We would write the following additional code: + + <pre> + string address; + + address = "138.95.19.14 12345"; + error = socket_connect(s, address, "read_callback", "write_callback"); + if (error != EESUCCESS) { + write("socket_connect: " + socket_error(error) + "\n"); + socket_close(s); + return; + } + </pre> + + Notice the address variable. It is a string and we asssign it the + Internet address and port number with a space in between to seperate + them. This is the format that socket_connect() expects addresses and + ports to be specified. + + So what are the read and write callback functions? Well we have already + talked about callbacks in general. MudOS calls these function when some + network event occurs. In these cases, MudOS calls the applications when + data becomes available to read (i.e. read callback) or that it is now + okay to write data (write callback). We will discuss how these callbacks + should work in just a bit. + + The point is, once socket_connect() is called, the client initiates a + connect request to the server. Because of the way MudOS works this is + all we can do for now. The network has work to do. We have just requested + the network to send a connect request to a remote machine. That remote + machine will then inform the application that a connect request has + been received and that application will decided what to do about it. The + point is, all of this takes time. And while all this is going on MudOS + has other work to do. So rather than stop MudOS from doing useful work, + MudOS simply return EESUCCESS. Does this mean that the connection has + been made? No. Does it mean the remote machine will connect with us? + No. Do we even know if the remote machine is up? No. Do we know + anything? Yes, a little. We know that three possible things can happen + in the near future. 1. the read callback function could be called + indicating the arrival of data from the remote application, 2. the write + callback could be called indicating that it is okay to send data, or 3. the + close callback function (that was provided way back in socket_create()) + could be closed indicating that the remote machine did not accept of + connection request. + + Before going one step further though, make sure this is all clear. + socket_connect() tells TCP to start a connection request. When + socket_connect() returns we don't know anything about the state of + the connection as of yet. MudOS will eventually call back one of the + functions so we know what happened. This sort of programming is called + asynchronuous programming. It's opposite is known as synchronous + programming. In synchronous programming your application would wait + until the connection is either accepted or closed before returning. + But we do not have the leisure of synchronous programming in MUDs because + while we wait for the network, other things are being ignored which should + not be. So to be fair to everyone we use this asynchronous model. Which is + not really that complicated once you get the hang of it. + + Of course, in the above discussion we assume you check the return value + from socket_connect() for EESUCCESS. If socket_connect() does not return + EESUCCESS then the connection request failed and no callbacks will be + called. A common mistake is to forget to check the return value and assume + one of the callbacks will eventually be called. Be careful. As in all cases + above if the connection request fails then be write an error message out to + the display, close the socket so it can be re-used and return. + + Now we wait. Some time in the future either the read, write or close + callback will be called... + + Accepting a Connection + + Meanwhile (back at the server) a connection request is received from the + client. When this occurs our listen callback function will be called. + This function was specified in the socket_listen() function, remember? + MudOS calls the listen callback with a single argument, that being the + socket descriptor of the socket that, socket_create(), socket_bind() and + socket_listen() was done on. This is useful if an object is listening + on multiple sockets at the same time. + + The responsibility of the listen callback function is too either + accept the connection or close it. In general though, as was mentioned + above, we always accept incoming connection requests. The following + code accepts an incoming connection request: + + <pre> + void + listen_callback(int s) + { + int ns; + + ns = socket_accept(s, "read_callback", "write_callback"); + if (ns < 0 && ns != EENOSOCKS) { + write("socket_connect: " + socket_error(error) + "\n"); + return; + } + } + </pre> + + Okay, we know what s is, right? It was passed as an argument to us. + It is the socket on which the connection indication came in on. So what + is ns? Aha! ns is an abbreviation for new socket. When a connection is + established a new socket is created for that connection. So what is s used + for? It is used to accept connections on. s will never be used, for + example, to actually send or receive data. Instead, it is used to tell + the socket application when connection requests arrive. ns, however, is + a socket that can communicate with the client. The server can send and + receive data on it etc. Make sense? + + Now if you recall, we passed read and write callback function names to + the socket_connect() efun. We are doing the same thing here. + We haven't discussed them yet so don't worry, we'll get there. For now + just realize that the read and write callbacks are used for the same + purpose for socket_accept() as they are for socket_connect(). And don't + get too impatient we are almost ready to discuss them in gory detail. + + It's important to note that our error handling is different here than in + other cases. If socket_accept() returns a value greater than or equal to + 0 then the efun succeeded just like socket_create(). This means that the + connection has been established! This is major progress. However if it + did not succeed there is one case that is worth making an exception for. + Recall from way, way back that there are a limited number of sockets that + MudOS can use? Well, what would happen if all sockets are in use when a + connection request arrived? Well simple, stated the connection could not + be accepted because there are no sockets to accept it on. This is a shame + but it can happen. If it does EENOSOCKS is returned. This is more of + a warning than a really bad error. Sure the connection was closed because + not sockets were available, but if some other socket becomes free a new + connection could be established in the future, so this is an example of + a temporary error. In this case, it may make sense to just return. + However, in all other cases, the listen socket is closed. This means that + no new connections can be accepted, until the server is restarted. As + a result be sure to display an error message so an administrator knows + to restart the server! + + <HR> + + Flow Control + + Before talking about data transfer which is sort of the climactic + section anyway, we need to discuss another paradigm. If we were + to look at networking technology today networks run at several orders + of magnitude of difference in performance. FDDI, for example, which is the + fiber opitc network standard of today runs at around 80 million bits per + second, IBM Token Ring runs around 16 million bits per second, Ethernet + around 10 millions bits per second, high-speed syncronous serial runs at + about 56 thousand bits per second and finally consumer asynchronous + modems run from 1.2 thousand to 14.4 thousand bits per second. These are + raw data rates, and one certainly cannot expect to use the entire + bandwidth of the various media. The point is this, if you ever expected + to find a hetrogeneous operating environment, networking is it. The same + protocols operate correctly at various data rates, and with different network + technologies. This is what the Internet model is all about. + + Because of the variety in networks today it is difficult to make assumption + about how long things might take on networks. Recall from about that when + we initiated a connect request from a client we checked to be sure that + socket_connect() return EESUCCESS and then just returned and waited? This + was not just a cute metaphor. In reality we were. On an Ethernet we + probably waited about 3/1000s of a second for a reply, not really all that + long. So short in fact, we could have probably just hung around for the + response and delayed further processing within MudOS. But what if the + reply were to take several seconds, which is is likely to do on a SLIP or + Point-to-Point link? We don't know a priori how long things will take and + so must be prepared for the worst when dealing with networks. + + There really is a point to all of this discussion. Computers are pretty + fast and are getting faster. Desktop computer can runs millions of + instructions per second. At best a similarly priced modem for such a + computer could run at around 19.2 thousand bits per second. That works + out to less than 2 thousand bytes per second. So if we compare the computer + speed to the network speed we find a vast difference in speed. The + conclusion one should reach is this: A computer can generate data much + faster than a network can send it. Therefore I could write a program + that sat in a loop and pounded the network with data, and it's very likely + that I would eventually run into a case where I had data ready to send and + the network is not ready to accept it. What should we do in this situation? + Well if we follow our previous example (i.e. socket_connect()) we would just + wait until the network is ready for more data. And so we do. + + Realizing the difference in speed between computers and networks the + inventor of network software have designed the following kind of interface. + Each socket has a reasonably-sized memory buffer (typically around 4k + bytes of data) that is used to temporary hold data while is waits for the + network to send it. This temporary buffer will eventually fill, of course, + if we were to send data faster than the network can handle. When it does the + socket is said to be "flow controlled". This mean we are told that there is + no more room in this temporary buffer to hold any more data, so we should + stop sending more data. This flow controlled notion affects is directly + when writing sockets code. We have to be smart enough to send when we + can and wait when we cannot send. This may sound complicated; luckily + we can reduce this down to a few very simple rules. + + Remember we said that socket_connect() generates a connection request and + returns immediately without waiting for the reply? This is true it does. + But what we didn't mention back then is that during the connection request + your application cannot send any data. This makes sense right? If the + connection has not been established then how can data be sent. This is + like dialing a phone number and starting to talk while the phone rings! + Well if we cannot send data after socket_connect(), when can we. We talked + about this before, remember? Once the connection is established then + either the read, write or close callback will be called. + + So if we want to send data what should we do? Wait for the write callback + procedure! Simple enough, right? Let's forget about the close callback + for the moment because we know why it gets called and it not important any- + more. Let's just focus on the read and write callback functions. We said + when the connection has been established either the read or write callback + function will be called. Well gee, if we are waiting for the connection + to come up so we can send data and our read callack gets called what should + we do, send the data? No. Because no matter what, once the connection + comes up the write callback is guaranteed to be called at least once. + In other words, there are two directions of communcation the read direction + (data coming across the network towards us) and the write direction (data we + send out the network towards the other MUD). If we stick to our guns + and think of each direction as seperate we will avoid confusion. + + Now remember the term flow-controlled? It means that we cannot send any + more data because we are waiting for the network to catch up. Well + after a connection request (i.e. socket_connect()) we are flow- + controlled. Once the connection has been accepted by the server then + our write callback function is called and we become, not flow-controlled! + This is our cue! Send data! Make sense? + + Ok, so we take our chance and start sending data like mad. The network + sends this, and this, and this too. At some point the buffer inside is + going to fill up and we are going to become flow-controlled again. What do + we do then? Same as before. Wait for our write callback function to be + called again so we can start sending more data. Sending on a network is + like send bits of data in bursts. We send, we wait, we send some more. + A correctly written socket application then is one who keeps track + of whether it can or not. And only sends when MudOS says it can, and + waits when MudOS says it cannot. + + Before you go off and get frustrated with LPC sockets, remember this: the + rules for flow control are not difficult to understand, but violating them + can end in disaster. Make sure you understand this flow control model. It + is fundamental to the asyncrhonous programming model. If it does not make + sense then please re-read this section or ask a sockets-savvy friend for + help, because this is very important. + + Sending data + + Okay, now that we understand the constraints within which we live, it's time + to discuss actually sending data. It's been a long time in coming, but we + have convered a lot of important information along the way. + + After a client's write callback is called the client is no longer + flow-controlled, which means it can begin writing data. What about the + server? Is the server flow-controlled after doing socket_accept()? This + is a good question. The answer is no, it is not. This is another difference + between clients and server. The client must wait for a write callback + before it can begin sending data, the server can begin as soon as the + connection has been accepted. Ignoring this final detail though, there + is no difference between client and servers send and receiving data. Both + client and server use the same socket efuns in the same way. + + So let's do it, let's send a number in MUD mode. + + <pre> + error = socket_write(s, 0); + </pre> + + Incredibly enough that's all it takes to send the LPC integer 0 to + the other MUD. One could do: + + <pre> + error = socket_write(s, "Hello you other MUD1"); + </pre> + + to send a hello message as a string to the other MUD. In fact in MUD mode + you can send any LPC data type except objects. This means arrays, mappings, + integers, etc. This is very powerful indeed! Ok we sent it, but what happened + on the other side so they can receive it? Remember the read callback + function, we specified it in the socket_connect() and socket_accept() + efuns? The read callback function is called when the network delivers to + the data to the socket. For example: + + <pre> + void + read_callback(int s, mixed message) + { + write("Received " + message + "\n"); + } + </pre> + + would write the receive data! The read callback then is used by MudOS + to tell an object when new data arrives. In the above example we used + a second parameter of mixed. This is because in MUD mode any data type + can be sent across the network. It is the object's responsibility to make + sure the object type is correct. In fact, once you are able to send and + receive data correctly, you have solved the immediate problem of communication + and have opened up a whole new problem called protocol engineering. This + involves designing networking protocols that are reliable and can + interoperate with many type of computers, but that unfortunately is far + beyond the scope of the tutorial. Alas. + + So have we finished with socket_write()? I hope you don't think so. + You should have noticed that we didn't check error after calling + socket_write(). Why is this? Well to be blunt, because there are four + different classes of return codes that socket_write() can return and I + figured we'd ease into the nitty gritty details. So here we go. + + There are four things socket_write() can return. 1) because it sent + the data along and everything is just fine, 2) the data has been saved in + a buffer and will eventually be sent, but no more data can be accomodated + at the moment, 3) the data has not been saved in a buffer and will not + be sent since no more data can be accomodated at the moment, and + 4) socket_write() is very confused and doesn't know what to do now. In the + first case, socket_write() has sent the data and is ready for more. It will + not call the write callback function because there is no need to, we are not + flow-controlled. In other words, we should remember that it is still okay + to send data. In the second case the data will be sent, it's sitting in a + memory buffer ready to be sent when the network can send it, but the buffer + is now full. Which means we are now flow-controlled. It would be + inappropriate for us to try to send more at this point, so we should remember + we cannot send any more right now. When the network empties the memory buffer + the write callback function will be called and we can then start sending data + again. In the third case, the data couldn't be sent at that moment, + possibly due to socket traffic or network congestion. We are not flow- + controlled so the write callback function must be called explicitly, to + attempt resending the data. A call_out() is a better choice here over + a direct function call since the delay gives the system a chance to recover, + reduces the possibility of max eval'ing, and better simulates a callback. + In the final case, some error has occurred either on the network connect or + within the operating system such that the write can not be performed. In + that case, however, it is likely nothing can be done to rectify the problem. + In general, the best thing to do is simply close the connection. In general, + this never happens. + + Okay so much for the abstract, let's look at the specifics. socket_write() + returns EESUCCESS in case (1) above. This means that further writes to the + socket are still possible. If socket_write() returns EECALLBACK, this + indicates that the data has been buffered for output, but that further writes + should be suspended until the write callback function is called. Conversely, + if socket_write() returns EEWOULDBLOCK, this indicates that the data has + not been buffered for output, and that the write callback function must be + called again manually (to resend) before further writes are attempted. + EEALREADY means that the object has violated the flow control model, + i.e. a write was done while the socket was flow-controlled. In this event, + the data is *not* buffered and the caller should again wait for the write + callback function. Of course, well written application will not see + EEALREADY. Any other return value should probably be interpreted as a fatal + error and the socket closed. + + <pre> + int socket_write(int, mixed, string|void); + int socket_release(int, object, string); + int socket_acquire(int, string, string, string); + string socket_address(int); + void dump_socket_status(void); + </pre> diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/for ds2.1/lib/doc/lpc/constructs/for *** ds1.1/lib/doc/lpc/constructs/for Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/for Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,28 ---- + * The LPC for loop: + + The LPC for loop is also identical to that provided by C. Syntax is as + follows: + + for (expression0; expression1; expression2) { + statements; + ...; + } + + Expression0 is evaluated once prior to the execution of the loop. Expression1 + is evaluated at the beginning of each iteration of the loop. If expression1 + evaluates to zero, then the loop terminates. Expression2 is evaluated at + the end of each loop iteration. + + A 'break' in the body of the loop will terminate the loop. A 'continue' will + continue the execution from the beginning of the loop (after evaluating + Expression2). + + A typical usage of the for loop is to execute a body of code some + fixed number of times: + + int i; + + for (i = 0; i < 10; i++) { + write("i == " + i + "\n"); + write("10 - i == " + (10 - i) + "\n"); + } diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/function ds2.1/lib/doc/lpc/constructs/function *** ds1.1/lib/doc/lpc/constructs/function Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/function Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,37 ---- + * The LPC function (or method): + + The LPC function is similar but not identical to that provided by C + (it is most similar to that provided by ANSI C). The syntax is as follows: + + return_type function_name(arg1_type arg1, arg2_type arg2, ...) + { + variable_declarations; + ...; + + statements; + ...; + return var0; + } + + Note that var0 must be of return_type. + + If a function doesn't need to return a value, then it should be declared + with a return_type of "void". E.g. + + void function_name(arg1_type arg1, ...) + { + statements; + ...; + } + + Invoke a function as follows: + + function_name(arg1, arg2, arg3, ...); + + You may invoke a function in another object as follows: + + object->function_name(arg1, arg2, arg3, ...); + + or: + + call_other(object, function_name, arg1, arg2, ...); diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/if ds2.1/lib/doc/lpc/constructs/if *** ds1.1/lib/doc/lpc/constructs/if Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/if Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,48 ---- + * The if else statement: + + LPC's if statement is identical to that provided by C. Syntax is as follows: + + if (expression) + statement; + + Alternately: + + if (expression) { + statements; + } + + Alternately: + + if (expression0) { + statements; + } else { + statements1; + } + + Alternately: + + if (expression0) { + statements0; + } else if (expression1) { + statements1; + } + + The number of else clauses is not explicitly limited. + + - - - - - + + Another favorite programming construct is the ? : operator, which also + operates identical to C. The syntax is: + + expression0 ? expression1_if_true : expression2_if_false + + In some cases, ? : is an shorter way of expression constructs such as: + + if (expression0) + var = expression1; + else + var = expression2; + + which can be equivalently translated to: + + var = expression0 ? expression1 : expression; diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/include ds2.1/lib/doc/lpc/constructs/include *** ds1.1/lib/doc/lpc/constructs/include Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/include Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,21 ---- + The LPC #include directive: + + Syntax: #include <file.h> + Alternate: #include "file.h" + + Note: the '#include "file.h"' form looks for file.h in the current directory. + The '#include <file.h>' form looks for file.h in one of the standard + system include directories (on TMI these directories are /include and + /local/include). + + For those that know C, the LPC #include statement is identical to C's + #include statement. For those that don't know C, the #include statement + is a way to textually include one file into another. Putting a statement + '#include "file.h" in a file gives the same effect as if you had simply + typed the contents of file.h directly into the file at the point where you + had the #include statement. Included files are recompiled each time the + object that include's them is recompiled. If the included file contains + variables or functions of the same name as variables in the file doing + the including, then a duplicate-name error will occur at compile time + (in the same way that the error would occur if you simply typed in file.h + rather than using #include). diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/inherit ds2.1/lib/doc/lpc/constructs/inherit *** ds1.1/lib/doc/lpc/constructs/inherit Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/inherit Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,46 ---- + The LPC inherit statement: + + Syntax: inherit pathname; + + where pathname is a full path delimited by quotes (e.g. "/std/Object"). + + The 'inherit' statement provides the inheritance capability (a concept from + object-oriented programming) to LPC objects. Inheritance lets an object + inherit functions and variables from other objects. Because the MudOSdriver + internally stores global data and compiled code separately, many different + objects can use inheritance to share the same piece of compiled code. Each of + these objects will have its own local copy of any global variables defined + by the object. Suppose that two object A and B inherit object C. Recompiling + object either of A or B will not cause C to be recompiled. However, it will + cause any global variables provided by C to lose whatever data they had + (remember that A and B each have their own copy of the global variables + provided by C. Thus updating A will not effect the global variables of B + (even those provided by C) and vice versa). + + Suppose object A inherits object B. Object A may define variables and functions + having the same names as those defined by B. If object A defines a function + of the same name as one defined by B, then the definition provided by A + overrides the definition provided by B. If A wishes to access the definition + provided by B, then it may do so. For example suppose that object A defines + its own function named query_long and yet wishes to call the query_long + function provided by the /std/Object.c object. Then A may refer to the + query_long in Object.c as Object::query_long(). If A defines a variable + of the same name as a global variable defined in B, then the only way that A + can access that variable is via functions provided by B. If B defines + a global variable that is not declared in A, then by default A may use that + global variable as if the global variable were defined in A (assuming B does + not choose to restrict access). Note: if object B is recompiled, object A + will continue to use the old version of object B until object A is also + recompiled. + + Multiple inheritance is allowed. That is, an object may inherit more than + one other object. Suppose special.c inherits weapon.c and armor.c and that + both weapon.c and armor.c each provide their own version of query_long(). + We may assume that special.c wants to sometimes act like a weapon and + sometimes act like armor. When special.c is to look like armor it + can use armor::query_long() and when it is to look like a weapon it + can use weapon::query_long(). + + See the tutorial named 'types/modifiers' for more information on how + inherited objects may hide data and function definitions from objects that + inherit them. diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/prototypes ds2.1/lib/doc/lpc/constructs/prototypes *** ds1.1/lib/doc/lpc/constructs/prototypes Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/prototypes Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,7 ---- + * The function prototype: + + The LPC function prototype is very similar to that of ANSI C. The + function prototype allows for better type checking and can serve as + a kind of 'forward' declaration. + + return_type function_name(arg1_type arg1, arg2_type arg2, ...); diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/switch ds2.1/lib/doc/lpc/constructs/switch *** ds1.1/lib/doc/lpc/constructs/switch Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/switch Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,31 ---- + * The switch statement. The LPC switch statement is nearly identical to + the C switch statement. The only real difference is that the cases of + the LPC switch may be strings as well as integers. Syntax is as follows: + + switch (expression) { + case constant0 : statements0; + break; + case constant1 : statements1; + break; + default : statements2; + break; + } + + The switch is a replacement for the chained if else if else if else + construct. The above switch is equivalent to: + + tmp = expression; + if (tmp == constant0) { + statements0; + ...; + } else if (tmp == constant1) { + statements1; + ...; + } else { + statements2; + ...; + } + + The main difference between the switch and the if statement is that if + the "break;" statement is ommited from the end of a particular case, + then the statements in the next case will be executed as well. diff -c -r --new-file ds1.1/lib/doc/lpc/constructs/while ds2.1/lib/doc/lpc/constructs/while *** ds1.1/lib/doc/lpc/constructs/while Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/constructs/while Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,40 ---- + The LPC while loop: + + LPC's while loop is identical to that provided by C. Syntax is as follows: + + while (expression) + statement; + + where statement may be replaced by a block of statements delimited by + matching curly brackets. For example: + + while (expression) { + statement0; + statement1; + } + + The statements inside the body of the while loop will be executed + repeatedly for as long as the test expression evaluates to non-zero. + If the test expression is zero just prior to the execution of the loop, + then the body of the loop will not be executed. A 'break;' statement + in the body of the loop will terminate the loop (skipping any statements + in the loop that remain to be executed). A 'continue;' statement + in the body of the loop will continue the execution from the beginning + of the loop (skipping the remainder of the statements in the loop for + the current iteration). + + int test(int limit) + { + total = 0; + j = 0; + while (j < limit) { + if ((j % 2) != 0) + continue; + total += j; + j++; + } + return total; + } + + The results of this code fragment will be to sum all of the even numbers + from 0 to to limit - 1. diff -c -r --new-file ds1.1/lib/doc/lpc/etc/error_msgs ds2.1/lib/doc/lpc/etc/error_msgs *** ds1.1/lib/doc/lpc/etc/error_msgs Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/etc/error_msgs Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,35 ---- + parse error + Variable <str> not declared ! + Illegal LHS + Illegal RHS + Undefined function <str> + Wrong number of arguments to <str> + syntax error + Illegal character (hex 2e) + Illegal character (hex 5c) + Illegal character constant + Redeclaration of function <str> + End of file in string + Function <str> undefined + Newline in string + Illegal terminator + Text block exceeded maximum length + Bad arg 1 to <str> + Return type not matching: <type> + Cannot #include <str> + Could not load description for <str> + Indexing on illegal type + Bad type argument to .+ 16 4 + Casts are only legal for type mixed, or when unknown: <type> + Redefinition of #define <str> + Bad argument number <int> to <str>: <type> + Invalid simulated efunction <str> + Missing type for argument + Bad type for argument <int> ( <type> vs <type> ) + Illegal to redeclare local name + Bad argument 1 type to efun <str> + Illegal to redefine 'nomask' function <str> + Must return a value for a function declared: <type> + Too many arguments to buffer + Internal error in <str> + Divide by zero in constant diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/Contents ds2.1/lib/doc/lpc/intermediate/Contents *** ds1.1/lib/doc/lpc/intermediate/Contents Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/Contents Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,15 ---- + Intermediate LPC + Descartes of Borg + November 1993 + + Contents + + 1: Introduction + 2: The LPMud Driver + 3: Complex Data Types + 4: The LPC Pre-Compiler + 5: Advanced String Handling + 6: Intermediate Inheritance + 7: Debugging + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/Copyright ds2.1/lib/doc/lpc/intermediate/Copyright *** ds1.1/lib/doc/lpc/intermediate/Copyright Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/Copyright Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,62 ---- + Intermediate LPC first edition + + Copyright (c) 1993 George Reese + All rights to this text are retained by the author. + + + Permission is granted to distrubute and display the contents of this + document in full so long as the following conditions are met: + 1) No payment may be received for the redistribution or display of this text, + except to cover the costs for distribution media and and shipping and/or + transmission charges. + 2) The textbook must be distributed or displayed in its entirety in its original + form. Changes may only be made to private, individual copies, except as + outlined below. + + Acceptable changes are defined as the following: + 1) Format changes, such as changing from WordPerfect to Word + 2) Medium changes, such as from electronic copy to paper + 3) Content changes are only acceptable under the following circumstances: + a) In electronic media: none of the original text may be ommitted. + You may add comments + as you feel necessary, so long as comments are enclosed in <* *> + and are accompanied by + the game name or real name of the author of the comments + b) In hard copy: none of the original text may be omitted, but it may + be struck out so long + as the content of the original text is visible. Comments may be made + in any form so long + as they are made in handwriting and they are signed by the author. + Comments which are typed or printed must be made in accordance with the + format for electronic media. + + Practically speaking, this is what I mean: + First, I wrote this mostly for mud admins to put onto their muds for learning + coders to read as they are learning to build realms. I did not do this for + someone else to make a buck. So if you charge money for redistributing it + or allowing someone else to see it, you are in violation of this copyright. + Unless you are simply charging for what it cost you to print up a copy or + what the diskettes and postage cost to mail it. + Second, I wrote this textbook, and I should receive credit/blame for what I + say, and others should receive credit/blame for what they say. For example, + if I said something completely wrong, and you simply corrected it, I would + be getting credit for something I did not do. Yet, if you comment according + to the outline above, you will be properly credited for your comments. + More important to me, however, is the practical effect of having hundreds of + copies of this textbook everywhere. If you change something I had right + without noting it as a comment, I will be blamed for spreading + misinformation. This problem is only compunded if the text is redistributed. + So I prefer my words to remain my own. But, when I make mistakes, or if + something I say does not fit your driver/mudlib, please comment it so people + will know. In addition, having the comments side-by-side allows people to + see other ideas, like how another driver might handle something. + + + I want to please note again, you may display this on your mud (like in /doc). + You do not need to + mail me for permission. I would not mind email, since it is nice to know + people are using it, but that is not required. Also, if you really feel I have + done such a wonderful job that you should pay money to use this, then give + $5 to your local ASPCA (or international equivalent). + + See the file titled Contents for a full list of textbook chapters. diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/chapter1 ds2.1/lib/doc/lpc/intermediate/chapter1 *** ds1.1/lib/doc/lpc/intermediate/chapter1 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/chapter1 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,143 ---- + Intermediate LPC + Descartes of Borg + Novermber 1993 + + Chapter 1: Introduction + + 1.1 LPC Basics + Anyone reading this textbook should either have read the textbook LPC + Basics or be familiar enough with mud realm coding such that not only are + they capable of building rooms and other such objects involved in area + coding, but they also have a good idea of what is going on when the code + they write is executing. If you do not feel you are at this point, then go + back and read LPC Basics before continuing. If you do so, you will find + that what you read here will be much more meaningful to you. + + 1.2 Goals of This Textbook + The introductory textbook was meant to take people new to LPC from + knowing nothing to being able to code a nice realm on any LPMud. There + is naturally much more to LPC and to LPMud building, however, than + building rooms, armours, monsters, and weapons. As you get into more + complicated concepts like guilds, or desire to do more involved things with + your realm, you will find the concepts detailed in LPC Basics to be lacking + in support for these projects. Intermediate LPC is designed to take you + beyond the simple realm building process into a full knowledge of LPC for + functioning as a realm builder on an LPMud. The task of mudlib building + itself is left to a later text. After reading this textbook and working through + it by experimenting with actual code, the reader should be able to code game + objects to fit any design or idea they have in mind, so long as I have been + successful. + + 1.3 An Overview + What more is there? Well many of you are quite aware that LPC supports + mappings and arrays and have been asking me why those were not detailed + in LPC Basics. I felt that those concepts were beyond the scope of what I + was trying to do with that textbook and were more fitting to this textbook. + But new tools are all fine and dandy, what matters, however, is what you + can do with those tools. The goal of LPC Basics was to get you to building + quality LPMud realms. Mappings and arrays are not necessary to do that. + The goal of this book is to allow you to code any idea you might want to + code in your area. That ability requires the knowledge of mappings and + arrays. + + Any idea you want to code in an LPMud is possible. LPC is a language + which is amazingly well suited to this task. All that prevents you from + coding your ideas is your knowledge of LPC or an inadequate mudlib or + your mudÕs theme or administrative policies. This textbook cannot make + the mudlib you are working with any better, and it cannot change the mud + theme or the mudÕs administrative policies. Never once think that LPC is + incapable of doing what you want to do. If your idea is prevented by + administrative policies or themes, then it is simply not an idea for your + current mud. If the mudlib is inadequate, talk to the people in charge of + your mudlib about what can be done at the mudlib level to facilitate it. You + would be surprised by what is actually in the mudlib you did not know + about. More important, after reading this textbook, you should be able to + read all of the mudlib code in your mudÕs mudlib and understand what is + going on at each line in the mudlib code. You may not as yet be able to + reproduce that code on your own, but at least you can understand what is + going on at the mudlib level. + + This textbook starts out with a discussion about what the LPMud driver is + doing. One nice thing about this textbook, in general it is completely driver + and mudlib independent (excepting for the Dworkin Game Driver). The + chapter on the game driver does not get into actual implementation, but + instead deals with what all game drivers basically do in order to run the + mud. + + Next I discuss those magic topics everyone wants to know more about, + arrays and mappings. Mappings may be simultaneously the easiest and + most difficult data type to understand. Since they are sort of complex arrays + in a loose sense, you really need to understand arrays before discussing + them. All the same, once you understand them, they are much easier than + arrays to use in real situations. At any rate, spend most of your time + working with that chapter, because it is probably the most difficult, yet most + useful chapter in the book. + + After that follows a brief chapter on the LPC pre-compiler, a tool you can + use for sorting out how your code will look before it gets sent to the + compiler. Despite my horrid intro to it here, this chapter is perhaps the + easiest chapter in the textbook. I put it after the mappings and arrays + chapter for exactly that reason. + + Strings are re-introduced next, going into more detail with how you can do + such things as advanced command handling by breaking up strings. Once + you understand arrays fairly well, this chapter should be really simple. + + The next chapter is the second most important in the book. It may be the + most important if you ever intend to go beyond the intermediate stage and + dive into mudlib coding. That chapter involves the complex ideas behind + LPC inheritance. Since the goal of this textbook is not to teach mudlib + programming, the chapter is not a detailed discussion on object oriented + programming. Understanding this chapter, however, will give you some + good insights into what is involved with object oriented programming, as + well as allow you to build more complex objects by overriding functions + and defining your own base classes. + + Finally, the textbook ends with a simple discussion of code debugging. + This is not an essential chapter, but instead it is meant as more of an + auxiliary supplement to what the knowledge you have accumulated so far. + + 1.4 Not Appearing in This Textbook + Perhaps what might appear to some as the most glaring omission of this + textbook is largely a political omission, shadows. Never have I ever + encountered an example of where a shadow was either the best or most + effecient manner of doing anything. It does not follow from that, however, + that there are no uses for shadows. My reasoning for omitting shadows + from this textbook is that the learner is best served by learning the concepts + in this textbook first and having spent time with them before dealing with + the subject of shadows. In that way, I feel the person learning LPC will be + better capable of judging the merits of using a shadow down the road. I + will discuss shadows in a future textbook. + + If you are someone who uses shadows some or a lot, please do not take the + above paragraph as a personal attack. There may be some perfectly valid + uses for shadows somewhere which I have yet to encounter. Nevertheless, + they are not the ideal way to accomplish any given task, and therefore they + are not considered for the purposes of this textbook an intermediate coding + tool. + + I have also omitted discussions of security and object oriented + programming. Both are quite obviously mudlib issues. Many people, + however, might take exception with my leaving out a discussion of object + oriented programming. I chose to leave that for a later text, since most area + builders code for the creativity, not for the computer science theory. In both + the intermediate and beginner textbooks, I have chosen only to discuss + theory where it is directly applicable to practical LPC programming. For + people who are starting out green in LPC and want to code the next great + mudlib, perhaps theory would be more useful. But for the purposes of this + book, a discussion of object oriented programming is simply a snoozer. I + do plan to get heavy into theory with the next textbook. + + 1.5 Summary + LPC is not difficult to learn. It is a language which, although pathetic + compared to any other language for performing most computer language + tasks, is incredibly powerful and unequalled for the tasks of building an + area in MUD type games. For the beginner, it allows you to easily jump in + and code useful objects without even knowing what you are doing. For the + intermediate person, it allows you to turn any idea you have into textual + virtual reality. And for the advanced person, itÕs object oriented features + can allow you to build one of the most popular games on the internet. What + you can do is simply limited by how much you know. And learning more + does not require a computer science degree. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/chapter2 ds2.1/lib/doc/lpc/intermediate/chapter2 *** ds1.1/lib/doc/lpc/intermediate/chapter2 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/chapter2 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,223 ---- + Intermediate LPC + Descartes of Borg + Novermber 1993 + + Chapter 2: The LPMud Driver + + 2.1 Review of Basic Driver/Mudlib Interaction + In the LPC Basics textbook, you learned a lot about the way the mudlib + works, specifically in relation to objects you code in order to build your + realm. Not much was discussed about the interaction between the + mudlib and the driver. You should know, however, that the driver + does the following: + 1) When an object is first loaded into memory, the driver will call + create() in native muds and reset() in compat muds. A creator + uses create() or reset() to give initial values to the object. + 2) At an interval setup by the game administrator, the driver calls the + function reset(). This allows the object to regenerate monsters and + such. Notice that in a compat mud, the same function is used to set up + initial values as is used to reset the room. + 3) Any time a living object comes in contact with an object of any sort, + the driver calls init() in the newly encountered object. This allows + newly encountered objects to give living objects commands to execute + through the add_action() efun, as well as perform other actions which + should happen whenever a living thing encounters a given object. + 4) The driver defines a set of functions known as efuns which are + available to all objects in the game. Examples of commonly used efuns + are: this_player(), this_object(), write(), say(), etc. + + 2.2 The Driver Cycle + The driver is a C program which runs the game. Its basic functions are + to accept connections from the outside world so people can login, + interpret the LPC code which defines LPC objects and how they + function in the game, and accept user input and call the appropriate LPC + functions which match the event. In its most simplest essence, it is an + unending loop. + + Once the game has booted up and is properly functioning (the boot up + process will be discussed in a future, advanced LPC textbook), the + driver enters a loop which does not terminate until the shutdown() efun + is legally called or a bug causes the driver program to crash. First off, + the driver handles any new incoming connections and passes control of + the connection to a login object. After that, the driver puts together a + table of commands which have been entered by users since the last cycle + of the driver. After the command table is assembled, all messages + scheduled to be sent to the connection from the last driver cycle are sent + out to the user. At this point, the driver goes through the table of + commands to be executed and executes each set of commands each + object has stored there. The driver ends its cycle by calling the function + heart_beat() in every object with a heart_beat() set and finally + performing all pending call outs. This chapter will not deal with the + handling of connections, but instead will focus on how the driver + handles user commands and heartbeats and call outs. + + 2.3 User Commands + As noted in section 1.2, the driver stores a list of commands for each + user to be executed each cycle. The commands list has the name of the + living object performing the command, the object which gave the living + object that command, and the function which is to be executed in order + to perform the command. The driver refers to the object which typed in + the command as the command giver. It is the command giver which + gets returned as this_player() in most cases. + + The driver starts at the top of the list of living objects with pending + commands, and successively performs each command it typed by calling + the function associated with the command and passing any arguments + the command giver gave as arguments to the function. As the driver + starts with the commands issued by a new living object, the command + giver variable is changed to be equal to the new living object, so that + during the sequence of functions initiated by that command, the efun + this_player() returns the object which issued the command. + + Let's look at the command buffer for an example player. Since the + execution of his last command, Bozo has typed "north" and "tell + descartes when is the next reboot". The command "north" is associated + with the function "Do_Move()" in the room Bozo is in (the command + "north" is automatically setup by the SetExits() efun in that room). The + command "tell" is not specifically listed as a command for the player, + however, in the player object there is a function called "cmd_hook()" + which is associated with the command "", which matches any possible + user input. + + Once the driver gets down to Bozo, the command giver variable is set to + the object which is Bozo. Then, seeing Bozo typed "north" and the + function "north" is associated with, the driver calls Bozo's_Room- + >Do_Move(0). An argument of 0 is passed to the function since Bozo + only typed the command "north" with no arguments. The room + naturally calls some functions it needs, all the while such that the efun + this_player() returns the object which is Bozo. Eventually, the room + object will call eventMoveLiving() in Bozo, which in turn calls the + move_object() efun. This efun is responsible for changing an object's + environment. + + When the environment of an object changes, the commands available to + it from objects in its previous environment as well as from its previous + environment are removed from the object. Once that is done, the driver + calls the efun init() in the new environment as well as in each object in + the new environment. During each of these calls to init(), the object + Bozo is still the command giver. Thus all add_action() efuns from this + move will apply to Bozo. Once all those calls are done, control passes + back from the move_object() efun to the eventMoveLiving() lfun in Bozo. + eventMoveLiving() returns control back to Do_Move() in the old room, + which returns 1 to signify to the driver that the command action was + successful. If the Do_Move() function had returned 0 for some reason, + the driver would have written "What?" (or whatever your driver's + default bad command message is) to Bozo. + + Once the first command returns 1, the driver proceeds on to Bozo's + second command, following much the same structure. Note that with + "tell descartes when is the next reboot", the driver passes "descartes + when is the next reboot" to the function associated with tell. That + function in turn has to decide what to do with that argument. After that + command returns either 1 or 0, the driver then proceeds on to the next + living object with commands pending, and so on until all living objects + with pending commands have had their commands performed. + + 2.4 The Efuns set_heart_beat() and call_out() + Once all commands are performed for objects with commands pending, + the driver then proceeds to call the heart_beat() function in all objects + listed with the driver as having heartbeats. Whenever an object calls the + efun set_heart_beat() with a non-zero argument (depending on your + driver, what non-zero number may be important, but in most cases you + call it with the int 1). The efun set_heart_beat() adds the object which + calls set_heart_beat() to the list of objects with heartbeats. If you call it + with an argument of 0, then it removes the object from the list of objects + with heartbeats. + + The most common use for heartbeats in the mudlib is to heal players and + monsters and perform combat. Once the driver has finished dealing with + the command list, it goes through the heartbeat list calling heart_beat() in + each object in the list. So for a player, for example, the driver will call + heart_beat() in the player which will: + 1) age the player + 2) heal the player according to a heal rate + 3) check to see if there are any hunted, hunting, or attacking objects + around + 4) perform an attack if step 3 returns true. + 5) any other things which need to happen automatically roughly every + second + + Note that the more objects which have heartbeats, the more processing + which has to happen every cycle the mud is up. Objects with heartbeats + are thus known as the major hog of CPU time on muds. + + The call_out() efun is used to perform timed function calls which do not + need to happen as often as heartbeats, or which just happen once. Call + outs let you specify the function in an object you want called. The + general formula for call outs is: + call_out(func, time, args); + The third argument specifying arguments is optional. The first argument + is a string representing the name of the function to be called. The second + argument is how many seconds should pass before the function gets + called. + + Practically speaking, when an object calls call_out(), it is added to a list + of objects with pending call outs with the amount of time of the call out + and the name of the function to be called. Each cycle of the driver, the + time is counted down until it becomes time for the function to be called. + When the time comes, the driver removes the object from the list of + objects with pending call outs and performs the call to the call out + function, passing any special args originally specified by the call out + function. + + If you want a to remove a pending call before it occurs, you need to use + the remove_call_out() efun, passing the name of the function being + called out. The driver will remove the next pending call out to that + function. This means you may have some ambiguity if more than one + call out is pending for the same function. + + In order to make a call out cyclical, you must reissue the call_out() efun + in the function you called out, since the driver automatically removes the + function from the call out table when a call out is performed. Example: + + void foo() { call_out("hello", 10); } + + void hello() { call_out("hello", 10); } + + will set up hello() to be called every 10 seconds after foo() is first called. + There are several things to be careful about here. First, you must watch + to make sure you do not structure your call outs to be recursive in any + unintended fashion. Second, compare what a set_heart_beat() does + when compared directly to what call_out() does. + + set_heart_beat(): + a) Adds this_object() to a table listing objects with heartbeats. + b) The function heart_beat() in this_object() gets called every single + driver cycle. + + call_out(): + a) Adds this_object(), the name of a function in this_object(), a time + delay, and a set of arguments to a table listing functions with pending + call outs. + b) The function named is called only once, and that call comes after the + specified delay. + + As you can see, there is a much greater memory overhead associated + with call outs for part (a), yet that there is a much greater CPU overhead + associated with heartbeats as shown in part (b), assuming that the delay + for the call out is greater than a single driver cycle. + + Clearly, you do not want to be issuing 1 second call outs, for then you + get the worst of both worlds. Similarly, you do not want to be having + heart beats in objects that can perform the same functions with call outs + of a greater duration than 1 second. I personally have heard much talk + about at what point you should use a call out over a heartbeat. What I + have mostly heard is that for single calls or for cycles of a duration + greater than 10 seconds, it is best to use a call out. For repetitive calls of + durations less than 10 seconds, you are better off using heartbeats. I do + not know if this is true, but I do not think following this can do any + harm. + + 2.5 Summary + Basic to a more in depth understanding of LPC is and understanding of + the way in which the driver interacts with the mudlib. You should now + understand the order in which the driver performs functions, as well as a + more detailed knowledge of the efuns this_player(), add_action(), and + move_object() and the lfun init(). In addition to this building upon + knowledge you got from the LPC Basics textbook, this chapter has + introduced call outs and heartbeats and the manner in which the driver + handles them. You should now have a basic understanding of call outs + and heartbeats such that you can experiment with them in your realm + code. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/chapter3 ds2.1/lib/doc/lpc/intermediate/chapter3 *** ds1.1/lib/doc/lpc/intermediate/chapter3 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/chapter3 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,476 ---- + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 3: Complex Data Types + + 3.1 Simple Data Types + In the textbook LPC Basics, you learned about the common, basic LPC + data types: int, string, object, void. Most important you learned that + many operations and functions behave differently based on the data type + of the variables upon which they are operating. Some operators and + functions will even give errors if you use them with the wrong data + types. For example, "a"+"b" is handled much differently than 1+1. + When you ass "a"+"b", you are adding "b" onto the end of "a" to get + "ab". On the other hand, when you add 1+1, you do not get 11, you get + 2 as you would expect. + + I refer to these data types as simple data types, because they atomic in + that they cannot be broken down into smaller component data types. + The object data type is a sort of exception, but you really cannot refer + individually to the components which make it up, so I refer to it as a + simple data type. + + This chapter introduces the concept of the complex data type, a data type + which is made up of units of simple data types. LPC has two common + complex data types, both kinds of arrays. First, there is the traditional + array which stores values in consecutive elements accessed by a number + representing which element they are stored in. Second is an associative + array called a mapping. A mapping associates to values together to + allow a more natural access to data. + + 3.2 The Values NULL and 0 + Before getting fully into arrays, there first should be a full understanding + of the concept of NULL versus the concept of 0. In LPC, a null value is + represented by the integer 0. Although the integer 0 and NULL are often + freely interchangeable, this interchangeability often leads to some great + confusion when you get into the realm of complex data types. You may + have even encountered such confusion while using strings. + + 0 represents a value which for integers means the value you add to + another value yet still retain the value added. This for any addition + operation on any data type, the ZERO value for that data type is the value + that you can add to any other value and get the original value. Thus: A + plus ZERO equals A where A is some value of a given data type and + ZERO is the ZERO value for that data type. This is not any sort of + official mathematical definition. There exists one, but I am not a + mathematician, so I have no idea what the term is. Thus for integers, 0 + is the ZERO value since 1 + 0 equals 1. + + NULL, on the other hand, is the absence of any value or meaning. The + LPC driver will interpret NULL as an integer 0 if it can make sense of it + in that context. In any context besides integer addition, A plus NULL + causes an error. NULL causes an error because adding valueless fields + in other data types to those data types makes no sense. + + Looking at this from another point of view, we can get the ZERO value + for strings by knowing what added to "a" will give us "a" as a result. + The answer is not 0, but instead "". With integers, interchanging NULL + and 0 was acceptable since 0 represents no value with respect to the + integer data type. This interchangeability is not true for other data types, + since their ZERO values do not represent no value. Namely, "" + represents a string of no length and is very different from 0. + + When you first declare any variable of any type, it has no value. Any + data type except integers therefore must be initialized somehow before + you perform any operation on it. Generally, initialization is done in the + create() function for global variables, or at the top of the local function + for local variables by assigning them some value, often the ZERO value + for that data type. For example, in the following code I want to build a + string with random words: + + string build_nonsense() { + string str; + int i; + + str = ""; /* Here str is initialized to the string + ZERO value */ + for(i=0; i<6; i++) { + switch(random(3)+1) { + case 1: str += "bing"; break; + case 2: str += "borg"; break; + case 3: str += "foo"; break; + } + if(i==5) str += ".\n"; + else str += " "; + } + return capitalize(str); + } + + If we had not initialized the variable str, an error would have resulted + from trying to add a string to a NULL value. Instead, this code first + initializes str to the ZERO value for strings, "". After that, it enters a + loop which makes 6 cycles, each time randomly adding one of three + possible words to the string. For all words except the last, an additional + blank character is added. For the last word, a period and a return + character are added. The function then exits the loop, capitalizes the + nonsense string, then exits. + + 3.3 Arrays in LPC + An array is a powerful complex data type of LPC which allows you to + access multiple values through a single variable. For instance, + Nightmare has an indefinite number of currencies in which players may + do business. Only five of those currencies, however, can be considered + hard currencies. A hard currency for the sake of this example is a + currency which is readily exchangeable for any other hard currency, + whereas a soft currency may only be bought, but not sold. In the bank, + there is a list of hard currencies to allow bank keepers to know which + currencies are in fact hard currencies. With simple data types, we would + have to perform the following nasty operation for every exchange + transaction: + + int exchange(string str) { + string from, to; + int amt; + + if(!str) return 0; + if(sscanf(str, "%d %s for %s", amt, from, to) != 3) + return 0; + if(from != "platinum" && from != "gold" && from != + "silver" && + from != "electrum" && from != "copper") { + notify_fail("We do not buy soft currencies!\n"); + return 0; + } + ... + } + + With five hard currencies, we have a rather simple example. After all it + took only two lines of code to represent the if statement which filtered + out bad currencies. But what if you had to check against all the names + which cannot be used to make characters in the game? There might be + 100 of those; would you want to write a 100 part if statement? + What if you wanted to add a currency to the list of hard currencies? That + means you would have to change every check in the game for hard + currencies to add one more part to the if clauses. Arrays allow you + simple access to groups of related data so that you do not have to deal + with each individual value every time you want to perform a group + operation. + + As a constant, an array might look like this: + ({ "platinum", "gold", "silver", "electrum", "copper" }) + which is an array of type string. Individual data values in arrays are + called elements, or sometimes members. In code, just as constant + strings are represented by surrounding them with "", constant arrays are + represented by being surrounded by ({ }), with individual elements of + the array being separated by a ,. + + You may have arrays of any LPC data type, simple or complex. Arrays + made up of mixes of values are called arrays of mixed type. In most + LPC drivers, you declare an array using a throw-back to C language + syntax for arrays. This syntax is often confusing for LPC coders + because the syntax has a meaning in C that simply does not translate into + LPC. Nevertheless, if we wanted an array of type string, we would + declare it in the following manner: + + string *arr; + + In other words, the data type of the elements it will contain followed by + a space and an asterisk. Remember, however, that this newly declared + string array has a NULL value in it at the time of declaration. + + 3.4 Using Arrays + You now should understand how to declare and recognize an array in + code. In order to understand how they work in code, let's review the + bank code, this time using arrays: + + string *hard_currencies; + + int exchange(string str) { + string from, to; + int amt; + + if(!str) return 0; + if(sscanf(str, "%d %s for %s", amt, from, to) != 3) + return 0; + if(member_array(from, hard_currencies) == -1) { + notify_fail("We do not buy soft currencies!\n"); + return 0; + } + ... + } + + This code assumes hard_currencies is a global variable and is initialized + in create() as: + hard_currencies = ({ "platinum", "gold", "electrum", "silver", + "copper" }); + Ideally, you would have hard currencies as a #define in a header file for + all objects to use, but #define is a topic for a later chapter. + + Once you know what the member_array() efun does, this method + certainly is much easier to read as well as is much more efficient and + easier to code. In fact, you can probably guess what the + member_array() efun does: It tells you if a given value is a member of + the array in question. Specifically here, we want to know if the currency + the player is trying to sell is an element in the hard_curencies array. + What might be confusing to you is, not only does member_array() tell us + if the value is an element in the array, but it in fact tells us which element + of the array the value is. + + How does it tell you which element? It is easier to understand arrays if + you think of the array variable as holding a number. In the value above, + for the sake of argument, we will say that hard_currencies holds the + value 179000. This value tells the driver where to look for the array + hard_currencies represents. Thus, hard_currencies points to a place + where the array values may be found. When someone is talking about + the first element of the array, they want the element located at 179000. + When the object needs the value of the second element of the array, it + looks at 179000 + one value, then 179000 plus two values for the third, + and so on. We can therefore access individual elements of an array by + their index, which is the number of values beyond the starting point of + the array we need to look to find the value. For the array + hard_currencies array: + "platinum" has an index of 0. + "gold" has an index of 1. + "electrum" has an index of 2. + "silver" has an index of 3. + "copper" has an index of 4. + + The efun member_array() thus returns the index of the element being + tested if it is in the array, or -1 if it is not in the array. In order to + reference an individual element in an array, you use its index number in + the following manner: + array_name[index_no] + Example: + hard_currencies[3] + where hard_currencies[3] would refer to "silver". + + So, you now should now several ways in which arrays appear either as + a whole or as individual elements. As a whole, you refer to an array + variable by its name and an array constant by enclosing the array in ({ }) + and separating elements by ,. Individually, you refer to array variables + by the array name followed by the element's index number enclosed in + [], and to array constants in the same way you would refer to simple data + types of the same type as the constant. Examples: + + Whole arrays: + variable: arr + constant: ({ "platinum", "gold", "electrum", "silver", "copper" }) + + Individual members of arrays: + variable: arr[2] + constant: "electrum" + + You can use these means of reference to do all the things you are used to + doing with other data types. You can assign values, use the values in + operations, pass the values as parameters to functions, and use the + values as return types. It is important to remember that when you are + treating an element alone as an individual, the individual element is not + itself an array (unless you are dealing with an array of arrays). In the + example above, the individual elements are strings. So that: + str = arr[3] + " and " + arr[1]; + will create str to equal "silver and gold". Although this seems simple + enough, many people new to arrays start to run into trouble when trying + to add elements to an array. When you are treating an array as a whole + and you wish to add a new element to it, you must do it by adding + another array. + + Note the following example: + string str1, str2; + string *arr; + + str1 = "hi"; + str2 = "bye"; + /* str1 + str2 equals "hibye" */ + arr = ({ str1 }) + ({ str2 }); + /* arr is equal to ({ str1, str2 }) */ + Before going any further, I have to note that this example gives an + extremely horrible way of building an array. You should set it: arr = ({ + str1, str2 }). The point of the example, however, is that you must add + like types together. If you try adding an element to an array as the data + type it is, you will get an error. Instead you have to treat it as an array of + a single element. + + 3.5 Mappings + One of the major advances made in LPMuds since they were created is + the mapping data type. People alternately refer to them as associative + arrays. Practically speaking, a mapping allows you freedom from the + association of a numerical index to a value which arrays require. + Instead, mappings allow you to associate values with indices which + actually have meaning to you, much like a relational database. + + In an array of 5 elements, you access those values solely by their integer + indices which cover the range 0 to 4. Imagine going back to the example + of money again. Players have money of different amounts and different + types. In the player object, you need a way to store the types of money + that exist as well as relate them to the amount of that currency type the + player has. The best way to do this with arrays would have been to + store an array of strings representing money types and an array of + integers representing values in the player object. This would result in + CPU-eating ugly code like this: + + int query_money(string type) { + int i; + + i = member_array(type, currencies); + if(i>-1 && i < sizeof(amounts)) /* sizeof efun + returns # of elements */ + return amounts[i]; + else return 0; + } + + And that is a simple query function. Look at an add function: + + void add_money(string type, int amt) { + string *tmp1; + int * tmp2; + int i, x, j, maxj; + + i = member_array(type, currencies); + if(i >= sizeof(amounts)) /* corrupt data, we are in + a bad way */ + return; + else if(i== -1) { + currencies += ({ type }); + amounts += ({ amt }); + return; + } + else { + amounts[i] += amt; + if(amounts[i] < 1) { + tmp1 = allocate(sizeof(currencies)-1); + tmp2 = allocate(sizeof(amounts)-1); + for(j=0, x =0, maxj=sizeof(tmp1); j < maxj; + j++) { + if(j==i) x = 1; + tmp1[j] = currencies[j+x]; + tmp2[j] = amounts[j+x]; + } + currencies = tmp1; + amounts = tmp2; + } + } + } + + That is really some nasty code to perform the rather simple concept of + adding some money. First, we figure out if the player has any of that + kind of money, and if so, which element of the currencies array it is. + After that, we have to check to see that the integrity of the currency data + has been maintained. If the index of the type in the currencies array is + greater than the highest index of the amounts array, then we have a + problem since the indices are our only way of relating the two arrays. + Once we know our data is in tact, if the currency type is not currently + held by the player, we simply tack on the type as a new element to the + currencies array and the amount as a new element to the amounts array. + Finally, if it is a currency the player currently has, we just add the + amount to the corresponding index in the amounts array. If the money + gets below 1, meaning having no money of that type, we want to clear + the currency out of memory. + + Subtracting an element from an array is no simple matter. Take, for + example, the result of the following: + + string *arr; + + arr = ({ "a", "b", "a" }); + arr -= ({ arr[2] }); + + What do you think the final value of arr is? Well, it is: + ({ "b", "a" }) + Subtracting arr[2] from the original array does not remove the third + element from the array. Instead, it subtracts the value of the third + element of the array from the array. And array subtraction removes the + first instance of the value from the array. Since we do not want to be + forced on counting on the elements of the array as being unique, we are + forced to go through some somersaults to remove the correct element + from both arrays in order to maintain the correspondence of the indices + in the two arrays. + + Mappings provide a better way. They allow you to directly associate the + money type with its value. Some people think of mappings as arrays + where you are not restricted to integers as indices. Truth is, mappings + are an entirely different concept in storing aggregate information. Arrays + force you to choose an index which is meaningful to the machine for + locating the appropriate data. The indices tell the machine how many + elements beyond the first value the value you desire can be found. With + mappings, you choose indices which are meaningful to you without + worrying about how that machine locates and stores it. + + You may recognize mappings in the following forms: + + constant values: + whole: ([ index:value, index:value ]) Ex: ([ "gold":10, "silver":20 ]) + element: 10 + + variable values: + whole: map (where map is the name of a mapping variable) + element: map["gold"] + + So now my monetary functions would look like: + + int query_money(string type) { return money[type]; } + + void add_money(string type, int amt) { + if(!money[type]) money[type] = amt; + else money[type] += amt; + if(money[type] < 1) + map_delete(money, type); /* this is for + MudOS */ + ...OR... + money = m_delete(money, type) /* for some + LPMud 3.* varieties */ + ... OR... + m_delete(money, type); /* for other LPMud 3.* + varieties */ + } + + Please notice first that the efuns for clearing a mapping element from the + mapping vary from driver to driver. Check with your driver's + documentation for the exact name an syntax of the relevant efun. + + As you can see immediately, you do not need to check the integrity of + your data since the values which interest you are inextricably bound to + one another in the mapping. Secondly, getting rid of useless values is a + simple efun call rather than a tricky, CPU-eating loop. Finally, the + query function is made up solely of a return instruction. + + You must declare and initialize any mapping before using it. + Declarations look like: + mapping map; + Whereas common initializations look like: + map = ([]); + map = allocate_mapping(10) ...OR... map = m_allocate(10); + map = ([ "gold": 20, "silver": 15 ]); + + As with other data types, there are rules defining how they work in + common operations like addition and subtraction: + ([ "gold":20, "silver":30 ]) + ([ "electrum":5 ]) + gives: + (["gold":20, "silver":30, "electrum":5]) + Although my demonstration shows a continuity of order, there is in fact + no guarantee of the order in which elements of mappings will stored. + Equivalence tests among mappings are therefore not a good thing. + + 3.6 Summary + Mappings and arrays can be built as complex as you need them to be. + You can have an array of mappings of arrays. Such a thing would be + declared like this: + + mapping *map_of_arrs; + which might look like: + ({ ([ ind1: ({ valA1, valA2}), ind2: ({valB1, valB2}) ]), ([ indX: + ({valX1,valX2}) ]) }) + + Mappings may use any data type as an index, including objects. + Mapping indices are often referred to as keys as well, a term from + databases. Always keep in mind that with any non-integer data type, + you must first initialize a variable before making use of it in common + operations such as addition and subtraction. In spite of the ease and + dynamics added to LPC coding by mappings and arrays, errors caused + by failing to initialize their values can be the most maddening experience + for people new to these data types. I would venture that a very high + percentage of all errors people experimenting with mappings and arrays + for the first time encounter are one of three error messages: + Indexing on illegal type. + Illegal index. + Bad argument 1 to (+ += - -=) /* insert your favourite operator */ + Error messages 1 and 3 are darn near almost always caused by a failure + to initialize the array or mapping in question. Error message 2 is caused + generally when you are trying to use an index in an initialized array + which does not exist. Also, for arrays, often people new to arrays will + get error message 3 because they try to add a single element to an array + by adding the initial array to the single element value instead of adding + an array of the single element to the initial array. Remember, add only + arrays to arrays. + + At this point, you should feel comfortable enough with mappings and + arrays to play with them. Expect to encounter the above error messages + a lot when first playing with these. The key to success with mappings is + in debugging all of these errors and seeing exactly what causes wholes + in your programming which allow you to try to work with uninitialized + mappings and arrays. Finally, go back through the basic room code and + look at things like the SetExits() (or the equivalent on your mudlib) + function. Chances are it makes use of mappings. In some instances, it + will use arrays as well for compatibility with mudlib.n. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/chapter4 ds2.1/lib/doc/lpc/intermediate/chapter4 *** ds1.1/lib/doc/lpc/intermediate/chapter4 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/chapter4 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,182 ---- + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 4: The LPC Pre-Compiler + + 4.1 Review + The previous chapter was quite heavy, so now I will slow down a bit so + you can digest and play with mappings and arrays by taking on the + rather simple topic of the LPC pre-compiler. By this point, however, + you should well understand how the driver interacts with the mudlib and + be able to code objects which use call outs and heart beats. In addition, + you should be coding simple objects which use mappings and arrays, + noting how these data types perform in objects. It is also a good idea to + start looking in detail at the actual mudlib code that makes up your mud. + See if you understand everything which is going on in your mudlibs + room and monster codes. For things you do not understand, ask the + people on your mud designated to answer creator coding questions. + + Pre-compiler is actually a bit of a misnomer since LPC code is never + truly compiled. Although this is changing with prototypes of newer + LPC drivers, LPC drivers interpret the LPC code written by creators + rather than compile it into binary format. Nevertheless, the LPC pre- + compiler functions still perform much like pre-compilers for compiled + languages in that pre-compiler directives are interpreted before the driver + even starts to look at object code. + + 4.2 Pre-compiler Directives + If you do not know what a pre-compiler is, you really do not need to + worry. With respect to LPC, it is basically a process which happens + before the driver begins to interpret LPC code which allows you to + perform actions upon the entire code found in your file. Since the code + is not yet interpreted, the pre-compiler process is involved before the file + exists as an object and before any LPC functions or instructions are ever + examined. The pre-compiler is thus working at the file level, meaning + that it does not deal with any code in inherited files. + + The pre-compiler searches a file sent to it for pre-compiler directives. + These are little instructions in the file meant only for the pre-compiler + and are not really part of the LPC language. A pre-compiler directive is + any line in a file beginning with a pound (#) sign. Pre-compiler + directives are generally used to construct what the final code of a file will + look at. The most common pre-compiler directives are: + + #define + #undefine + #include + #ifdef + #ifndef + #if + #elseif + #else + #endif + #pragma + + Most realm coders on muds use exclusively the directives #define and + #include. The other directives you may see often and should understand + what they mean even if you never use them. + + The first pair of directives are: + #define + #undefine + + The #define directive sets up a set of characters which will be replaced + any where they exist in the code at precompiler time with their definition. + For example, take: + + #define OB_USER "/std/user" + + This directive has the pre-compiler search the entire file for instances of + OB_USER. Everywhere it sees OB_USER, it replaces with "/std/user". + Note that it does not make OB_USER a variable in the code. The LPC + interpreter never sees the OB_USER label. As stated above, the pre- + compiler is a process which takes place before code interpretation. So + what you wrote as: + + #define OB_USER "/std/user" + + void create() { + if(!file_exists(OB_USER+".c")) write("Merde! No user file!"); + else write("Good! User file still exists!"); + } + + would arrive at the LPC interpreter as: + + void create() { + if(!file_exists("/std/user"+".c")) write("Merde! No user file!"); + else write("Good! User file still exists!"); + } + + Simply put, #define just literally replaces the defined label with whatever + follows it. You may also use #define in a special instance where no + value follows. This is called a binary definition. For example: + + #define __NIGHTMARE + + exists in the config file for the Nightmare Mudlib. This allows for pre- + compiler tests which will be described later in the chapter. + + The other pre-compiler directive you are likely to use often is #include. + As the name implies, #include includes the contents of another file right + into the file being pre-compiled at the point in the file where the directive + is placed. Files made for inclusion into other files are often called header + files. They sometimes contain things like #define directives used by + multiple files and function declarations for the file. The traditional file + extension to header files is .h. + + Include directives follow one of 2 syntax's: + + #include <filename> + #include "filename" + + If you give the absolute name of the file, then which syntax you use is + irrelevant. How you enclose the file name determines how the pre- + compiler searches for the header files. The pre-compiler first searches in + system include directories for files enclosed in <>. For files enclosed in + "", the pre-compiler begins its search in the same directory as the file + going through the pre-compiler. Either way, the pre-compiler will + search the system include directories and the directory of the file for the + header file before giving up. The syntax simply determines the order. + + The simplest pre-compiler directive is the #pragma directive. It is + doubtful you will ever use this one. Basically, you follow the directive + with some keyword which is meaningful to your driver. The only + keyword I have ever seen is strict_types, which simply lets the driver + know you want this file interpreted with strict data typing. I doubt you + will ever need to use this, and you may never even see it. I just included + it in the list in the event you do see it so you do not think it is doing + anything truly meaningful. + + The final group of pre-compiler directives are the conditional pre- + compiler directives. They allow you to pre-compile the file one way + given the truth value of an expression, otherwise pre-compile the file + another way. This is mostly useful for making code portable among + mudlibs, since putting the m_delete() efun in code on a MudOS mud + would normally cause an error, for example. So you might write the + following: + + #ifdef MUDOS + map_delete(map, key); + #else + map = m_delete(map, key); + #endif + + which after being passed through the pre-compiler will appear to the + interpreter as: + + map_delete(map, key); + + on a MudOS mud, and: + + map = m_delete(map, key); + + on other muds. The interpreter never sees the function call that would + cause it to spam out in error. + + Notice that my example made use of a binary definition as described + above. Binary definitions allow you to pass certain code to the + interpreter based on what driver or mudlib you are using, among other + conditions. + + 4.3 Summary + The pre-compiler is a useful LPC tool for maintaining modularity among + your programs. When you have values that might be subject to change, + but are used widely throughout your files, you might stick all of those + values in a header file as #define statements so that any need to make a + future change will cause you to need to change just the #define directive. + A very good example of where this would be useful would be a header + file called money.h which includes the directive: + #define HARD_CURRENCIES ({ "gold", "platinum", "silver", + "electrum", "copper" }) + so that if ever you wanted to add a new hard currency, you only need + change this directive in order to update all files needing to know what the + hard currencies are. + + The LPC pre-compiler also allows you to write code which can be + ported without change among different mudlibs and drivers. Finally, + you should be aware that the pre-compiler only accepts lines ending in + carriage returns. If you want a multiple line pre-compiler directive, you + need to end each incomplete line with a backslash(\). + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/chapter5 ds2.1/lib/doc/lpc/intermediate/chapter5 *** ds1.1/lib/doc/lpc/intermediate/chapter5 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/chapter5 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,181 ---- + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 5: Advanced String Handling + + 5.1 What a String Is + The LPC Basics textbook taught strings as simple data types. LPC + generally deals with strings in such a matter. The underlying driver + program, however, is written in C, which has no string data type. The + driver in fact sees strings as a complex data type made up of an array of + characters, a simple C data type. LPC, on the other hand does not + recognize a character data type (there may actually be a driver or two out + there which do recognize the character as a data type, but in general not). + The net effect is that there are some array-like things you can do with + strings that you cannot do with other LPC data types. + + The first efun regarding strings you should learn is the strlen() efun. + This efun returns the length in characters of an LPC string, and is thus + the string equivalent to sizeof() for arrays. Just from the behaviour of + this efun, you can see that the driver treats a string as if it were made up + of smaller elements. In this chapter, you will learn how to deal with + strings on a more basic level, as characters and sub strings. + + 5.2 Strings as Character Arrays + You can do nearly anything with strings that you can do with arrays, + except assign values on a character basis. At the most basic, you can + actually refer to character constants by enclosing them in '' (single + quotes). 'a' and "a" are therefore very different things in LPC. 'a' + represents a character which cannot be used in assignment statements or + any other operations except comparison evaluations. "a" on the other + hand is a string made up of a single character. You can add and subtract + other strings to it and assign it as a value to a variable. + + With string variables, you can access the individual characters to run + comparisons against character constants using exactly the same syntax + that is used with arrays. In other words, the statement: + if(str[2] == 'a') + is a valid LPC statement comparing the second character in the str string + to the character 'a'. You have to be very careful that you are not + comparing elements of arrays to characters, nor are you comparing + characters of strings to strings. + + LPC also allows you to access several characters together using LPC's + range operator ..: + if(str[0..1] == "ab") + In other words, you can look for the string which is formed by the + characters 0 through 1 in the string str. As with arrays, you must be + careful when using indexing or range operators so that you do not try to + reference an index number larger than the last index. Doing so will + result in an error. + + Now you can see a couple of similarities between strings and arrays: + 1) You may index on both to access the values of individual elements. + a) The individual elements of strings are characters + b) The individual elements of arrays match the data type of the + array. + 2) You may operate on a range of values + a) Ex: "abcdef"[1..3] is the string "bcd" + b) Ex: ({ 1, 2, 3, 4, 5 })[1..3] is the int array ({ 2, 3, 4 }) + + And of course, you should always keep in mind the fundamental + difference: a string is not made up of a more fundamental LPC data type. + In other words, you may not act on the individual characters by + assigning them values. + + 5.3 The Efun sscanf() + You cannot do any decent string handling in LPC without using + sscanf(). Without it, you are left trying to play with the full strings + passed by command statements to the command functions. In other + words, you could not handle a command like: "give sword to leo", since + you would have no way of separating "sword to leo" into its constituent + parts. Commands such as these therefore use this efun in order to use + commands with multiple arguments or to make commands more + "English-like". + + Most people find the manual entries for sscanf() to be rather difficult + reading. The function does not lend itself well to the format used by + manual entries. As I said above, the function is used to take a string and + break it into usable parts. Technically it is supposed to take a string and + scan it into one or more variables of varying types. Take the example + above: + + int give(string str) { + string what, whom; + + if(!str) return notify_fail("Give what to whom?\n"); + if(sscanf(str, "%s to %s", what, whom) != 2) + return notify_fail("Give what to whom?\n"); + ... rest of give code ... + } + + The efun sscanf() takes three or more arguments. The first argument is + the string you want scanned. The second argument is called a control + string. The control string is a model which demonstrates in what form + the original string is written, and how it should be divided up. The rest + of the arguments are variables to which you will assign values based + upon the control string. + + The control string is made up of three different types of elements: 1) + constants, 2) variable arguments to be scanned, and 3) variable + arguments to be discarded. You must have as many of the variable + arguments in sscanf() as you have elements of type 2 in your control + string. In the above example, the control string was "%s to %s", which + is a three element control string made up of one constant part (" to "), + and two variable arguments to be scanned ("%s"). There were no + variables to be discarded. + + The control string basically indicates that the function should find the + string " to " in the string str. Whatever comes before that constant will + be placed into the first variable argument as a string. The same thing + will happen to whatever comes after the constant. + + Variable elements are noted by a "%" sign followed by a code for + decoding them. If the variable element is to be discarded, the "%" sign + is followed by the "*" as well as the code for decoding the variable. + Common codes for variable element decoding are "s" for strings and "d" + for integers. In addition, your mudlib may support other conversion + codes, such as "f" for float. So in the two examples above, the "%s" in + the control string indicates that whatever lies in the original string in the + corresponding place will be scanned into a new variable as a string. + + A simple exercise. How would you turn the string "145" into an + integer? + + Answer: + int x; + sscanf("145", "%d", x); + + After the sscanf() function, x will equal the integer 145. + + Whenever you scan a string against a control string, the function + searches the original string for the first instance of the first constant in + the original string. For example, if your string is "magic attack 100" and + you have the following: + int improve(string str) { + string skill; + int x; + + if(sscanf(str, "%s %d", skill, x) != 2) return 0; + ... + } + you would find that you have come up with the wrong return value for + sscanf() (more on the return values later). The control string, "%s %d", + is made up of to variables to be scanned and one constant. The constant + is " ". So the function searches the original string for the first instance + of " ", placing whatever comes before the " " into skill, and trying to + place whatever comes after the " " into x. This separates "magic attack + 100" into the components "magic" and "attack 100". The function, + however, cannot make heads or tales of "attack 100" as an integer, so it + returns 1, meaning that 1 variable value was successfully scanned + ("magic" into skill). + + Perhaps you guessed from the above examples, but the efun sscanf() + returns an int, which is the number of variables into which values from + the original string were successfully scanned. Some examples with + return values for you to examine: + + sscanf("swo rd descartes", "%s to %s", str1, str2) return: 0 + sscanf("swo rd descartes", "%s %s", str1, str2) return: 2 + sscanf("200 gold to descartes", "%d %s to %s", x, str1, str2) return: 3 + sscanf("200 gold to descartes", "%d %*s to %s", x, str1) return: 2 + where x is an int and str1 and str2 are string + + 5.4 Summary + LPC strings can be thought of as arrays of characters, yet always + keeping in mind that LPC does not have the character data type (with + most, but not all drivers). Since the character is not a true LPC data + type, you cannot act upon individual characters in an LPC string in the + same manner you would act upon different data types. Noticing the + intimate relationship between strings and arrays nevertheless makes it + easier to understand such concepts as the range operator and indexing on + strings. + + There are efuns other than sscanf() which involve advanced string + handling, however, they are not needed nearly as often. You should + check on your mud for man or help files on the efuns: explode(), + implode(), replace_string(), sprintf(). All of these are very valuable + tools, especially if you intend to do coding at the mudlib level. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/chapter6 ds2.1/lib/doc/lpc/intermediate/chapter6 *** ds1.1/lib/doc/lpc/intermediate/chapter6 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/chapter6 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,276 ---- + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 6: Intermediate Inheritance + + 6.1 Basics of Inheritance + In the textbook LPC Basics, you learned how it is the mudlib maintains + consistency amoung mud objects through inheritance. Inheritance + allows the mud administrators to code the basic functions and such that + all mudlib objects, or all mudlib objects of a certain type must have so + that you can concentrate on creating the functions which make these + objects different. When you build a room, or a weapon, or a monster, + you are taking a set of functions already written for you and inheriting + them into your object. In this way, all objects on the mud can count on + other objects to behave in a certain manner. For instance, player objects + can rely on the fact that all room objects will have a function in them + called GetLong() which describes the room. Inheritance thus keeps + you from having to worry about what the function GetLong() should + look like. + + Naturally, this textbook tries to go beyond this fundamental knowledge + of inheritance to give the coder a better undertstanding of how + inheritance works in LPC programming. Without getting into detail that + the advanced domain coder/beginner mudlib coder simply does not yet + need, this chapter will try to explain exactly what happens when you + inherit an object. + + 6.2 Cloning and Inheritance + Whenever a file is referenced for the first time as an object (as opposed + to reading the contents of the file), the game tries to load the file into + memory and create an object. If the object is successfully loaded into + memory, it becomes as master copy. Master copies of objects may be + cloned but not used as actual game objects. The master copy is used to + support any clone objects in the game. + + The master copy is the source of one of the controversies of mud LPC + coding, that is whether to clone or inherit. With rooms, there is no + question of what you wish to do, since there should only be one instance + of each room object in the game. So you generally use inheritance in + creating rooms. Many mud administrators, including myself, however + encourage creators to clone the standard monster object and configure it + from inside room objects instead of keeping monsters in separate files + which inherit the standard monster object. + + As I stated above, each time a file is referenced to create an object, a + master copy is loaded into memory. When you do something like: + void reset() { + object ob; + ob = new("/std/monster"); + /* clone_object("/std/monster") some places */ + ob->SetKeyName("foo monster"); + ... rest of monster config code followed by moving + it to the room ... + } + the driver searches to see if their is a master object called "/std/monster". + If not, it creates one. If it does exist, or after it has been created, the + driver then creates a clone object called "/std/monster#<number>". If + this is the first time "/std/monster" is being referenced, in effect, two + objects are being created: the master object and the cloned instance. + + On the other hand, let's say you did all your configuring in the create() + of a special monster file which inherits "/std/monster". Instead of + cloning the standard monster object from your room, you clone your + monster file. If the standard monster has not been loaded, it gets loaded + since your monster inherits it. In addition, a master copy of your file + gets loaded into memory. Finally, a clone of your monster is created + and moved into the room, for a total of three objects added to the game. + Note that you cannot make use of the master copy easily to get around + this. If, for example, you were to do: + "/realms/descartes/my_monster"->eventMove(this_object()); + instead of + new("/realms/descartes/my_monster")->eventMove(this_object()); + you would not be able to modify the file "my_monster.c" and update it, + since the update command destroys the current master version of an + object. On some mudlibs it also loads the new version into memory. + Imagine the look on a player's face when their monster disappears in + mid-combat cause you updated the file! + + Cloning is therefore a useful too when you plan on doing just that- + cloning. If you are doing nothing special to a monster which cannot be + done through a few call others, then you will save the mud from getting + loaded with useless master copies. Inheritance, however, is useful if + you plan to add functionality to an object (write your own functions) or + if you have a single configuration that gets used over and over again + (you have an army of orc guards all the same, so you write a special orc + file and clone it). + + 6.3 Inside Inheritance + When objects A and B inherit object C, all three objects have their own + set of data sharing one set of function definitions from object C. In + addition, A and B will have separate functions definitions which were + entered separately into their code. For the sake of example throughout + the rest of the chapter, we will use the following code. Do not be + disturbed if, at this point, some of the code makes no sense: + + STD_ITEM C + private string name, cap_name, short, long; + private int setup; + + void SetKeyName(string str) + nomask string GetKeyName(); + private int query_setup(); + static void unsetup(); + void SetShort(string str); + string GetShort(); + void SetLong(string str); + string GetLong(); + + + void SetKeyName(string str) { + if(!query_setup()) { + name = str; + setup = 1; + } + + nomask string GetKeyName() { return name; } + + private query_setup() { return setup; } + + static void unsetup() { setup = 0; } + + string GetName() { + return (name ? capitalize(name) : ""); } + } + + void SetShort(string str) { short = str; } + + string GetShort() { return short; } + + void SetLong(string str) { long = str; } + + string GetLong() { return str; } + + void create() { seteuid(getuid()); } + + STD_ITEM B + inherit "/std/objectc"; + + private int wc; + + void set_wc(int wc); + int query_wc(); + int wieldweapon(string str); + + void create() { ::create(); } + + void init() { + if(environment(this_object()) == this_player()) + add_action("wieldweapon", "wield"); + } + + void set_wc(int x) { wc = x; } + + int query_wc() { return wc; } + + int wieldweapon(string str) { + ... code for wielding the weapon ... + } + + STD_ITEM A + inherit "/std/objectc"; + + int ghost; + + void create() { ::create(); } + + void change_name(string str) { + if(!((int)this_object()->is_player())) unsetup(); + SetKeyName(str); + } + + string GetName() { + if(ghost) return "A ghost"; + else return ::GetName(); + } + + As you can see, object C is inherited both by object A and object B. + Object C is a representation of a much oversimplified base object, with B + being an equally oversimplified weapon and A being an equally + simplified living object. Only one copy of each function is retained in + memory, even though we have here three objects using the functions. + There are of course, three instances of the variables from Object C in + memory, with one instance of the variables of Object A and Object B in + memory. Each object thus gets its own data. + + 6.4 Function and Variable Labels + Notice that many of the functions above are proceeded with labels which + have not yet appeared in either this text or the beginner text, the labels + static, private, and nomask. These labels define special priveledges + which an object may have to its data and member functions. Functions + you have used up to this point have the default label public. This is + default to such a degree, some drivers do not support the labeling. + + A public variable is available to any object down the inheritance tree + from the object in which the variable is declared. Public variables in + object C may be accessed by both objects A and B. Similarly, public + functions may be called by any object down the inheritance tree from the + object in which they are declared. + + The opposite of public is of course private. A private variable or + function may only be referenced from inside the object which declares it. + If object A or B tried to make any reference to any of the variables in + object C, an error would result, since the variables are said to be out of + scope, or not available to inheriting classes due to their private labels. + Functions, however, provide a unique challenge which variables do not. + External objects in LPC have the ability to call functions in other objects + through call others. The private label does not protect against call + others. + + To protect against call others, functions use the label static. A function + which is static may only be called from inside the complete object or + from the game driver. By complete object, I mean object A can call + static functions in the object C it inherits. The static only protects against + external call others. In addition, this_object()->foo() is considered an + internal call as far as the static label goes. + + Since variables cannot be referenced externally, there is no need for an + equivalent label for them. Somewhere along the line, someone decided + to muddy up the waters and use the static label with variables to have a + completely separate meaning. What is even more maddening is that this + label has nothing to do with what it means in the C programming + language. A static variable is simply a variable that does not get saved to + file through the efun save_object() and does not get restored through + restore_object(). Go figure. + + In general, it is good practice to have private variables with public + functions, using query_*() functions to access the values of inherited + variables, and set_*(), add_*(), and other such functions to change + those values. In realm coding this is not something one really has to + worry a lot about. As a matter of fact, in realm coding you do not have + to know much of anything which is in this chapter. To be come a really + good realm coder, however, you have to be able to read the mudlib + code. And mudlib code is full of these labels. So you should work + around with these labels until you can read code and understand why it + is written that way and what it means to objects which inherit the code. + + The final label is nomask, and it deals with a property of inheritance + which allows you to rewrite functions which have already been defined. + For example, you can see above that object A rewrote the function + GetName(). A rewrite of function is called overriding the + function. The most common override of a function would be in a case + like this, where a condition peculiar to our object (object A) needs to + happen on a call ot the function under certain circumstances. Putting test + code into object C just so object A can be a ghost is plain silly. So + instead, we override GetName() in object A, testing to see if the + object is a ghost. If so, we change what happens when another object + queries for the cap name. If it is not a ghost, then we want the regular + object behaviour to happen. We therefore use the scope resolution + operator (::) to call the inherited version of the GetName() + function and return its value. + + A nomask function is one which cannot be overridden either through + inheritance or through shadowing. Shadowing is a sort of backwards + inheritance which will be detailed in the advanced LPC textbook. In the + example above, neither object A nor object B (nor any other object for + that matter) can override GetKeyName(). Since we want to use + GetKeyName() as a unique identifier of objects, we don't want people + faking us through shadowing or inheritance. The function therefore gets + the nomask label. + + 6.5 Summary + Through inheritance, a coder may make user of functions defined in + other objects in order to reduce the tedium of producing masses of + similar objects and to increase the consistency of object behaviour across + mudlib objects. LPC inheritance allows objects maximum priveledges in + defining how their data can be accessed by external objects as well as + objects inheriting them. This data security is maintained through the + keywords, nomask, private, and static. + + In addition, a coder is able to change the functionality of non-protected + functions by overriding them. Even in the process of overriding a + function, however, an object may access the original function through + the scope resolution operator. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/intermediate/chapter7 ds2.1/lib/doc/lpc/intermediate/chapter7 *** ds1.1/lib/doc/lpc/intermediate/chapter7 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/intermediate/chapter7 Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,298 ---- + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 7: Debugging + + 7.1 Types of Errors + By now, you have likely run into errors here, there, and everywhere. In + general, there are three sorts of errors you might see: compile time + errors, run time errors, and malfunctioning code. On most muds you + will find a personal file where your compile time errors are logged. For + the most part, this file can be found either in your home directory as the + file named "log" or ".log", or somewhere in the directory "/log" as a file + with your name.. In addition, muds tend to keep a log of run time errors + which occur while the mud is up. Again, this is generally found in + "/log". On MudOS muds it is called "debug.log". On other muds it may + be called something different like "lpmud.log". Ask your administrators + where compile time and run time errors are each logged if you do not + already know. + + Compile time errors are errors which occur when the driver tries to load + an object into memory. If, when the driver is trying to load an object + into memory, it encounters things which it simply does not understand + with respect to what you wrote, it will fail to load it into memory and log + why it could not load the object into your personal error log. The most + common compile time errors are typos, missing or extra (), {}. [], or "", + and failure to declare properly functions and variables used by the + object. + + Run time errors occur when something wrong happens to an object in + memory while it is executing a statement. For example, the driver + cannot tell whether the statement "x/y" will be valid in all circumstances. + In fact, it is a valid LPC expression. Yet, if the value of y is 0, then a + run time error will occur since you cannot divide by 0. When the driver + runs across an error during the execution of a function, it aborts + execution of the function and logs an error to the game's run time error + log. It will also show the error to this_player(), if defined, if the player + is a creator, or it will show "What?" to players. Most common causes + for run time errors are bad values and trying to perform operations with + data types for which those operations are not defined. + + The most insideous type of error, however, is plain malfunctioning + code. These errors do not log, since the driver never really realizes that + anything is wrong. In short, this error happens when you think the code + says one thing, but in fact it says another thing. People too often + encounter this bug and automatically insist that it must be a mudlib or + driver bug. Everyone makes all types of errors though, and more often + than not when code is not functioning the way you should, it will be + because you misread it. + + 7.2 Debugging Compile Time Errors + Compile time errors are certainly the most common and simplest bugs to + debug. New coders often get frustrated by them due to the obscure + nature of some error messages. Nevertheless, once a person becomes + used to the error messages generated by their driver, debugging compile + time errors becomes utterly routine. + + In your error log, the driver will tell you the type of error and on which + line it finally noticed there was an error. Note that this is not on which + line the actual error necessarily exists. The most common compile time + error, besides the typo, is the missing or superfluous parentheses, + brackets, braces, or quotes. Yet this error is the one that most baffles + new coders, since the driver will not notice the missing or extra piece + until well after the original. Take for example the following code: + + 1 int test(string str) { + 2 int x; + 3 for(x =0; x<10; x++) + 4 write(x+"\n"); + 5 } + 6 write("Done.\n"); + 7 } + + Depending on what you intended, the actual error here is either at line 3 + (meaning you are missing a {) or at line 5 (meaing you have an extra }). + Nevertheless, the driver will report that it found an error when it gets to + line 6. The actual driver message may vary from driver to driver, but no + matter which driver, you will see an error on line 6, since the } in line 5 + is interpreted as ending the function test(). At line 6, the driver sees that + you have a write() sitting outside any function definition, and thus + reports an error. Generally, the driver will also go on to report that it + found an error at line 7 in the form of an extra }. + + The secret to debugging these is coding style. Having closing } match + up vertically with the clauses they close out helps you see where you are + missing them when you are debugging code. Similarly, when using + multiple sets of parentheses, space out different groups like this: + if( (x=sizeof(who=users()) > ( (y+z)/(a-b) + (-(random(7))) ) ) + As you can see, the parentheses for the for() statement, are spaced out + from the rest of the statement. In addition, individual sub-groups are + spaced so they can easily be sorted out in the event of an error. + + Once you have a coding style which aids in picking these out, you learn + which error messages tend to indicate this sort of error. When + debugging this sort of error, you then view a section of code before and + after the line in question. In most all cases, you will catch the bug right + off. + + Another common compile time error is where the driver reports an + unknown identifier. Generally, typos and failure to declare variables + causes this sort of error. Fortunately, the error log will almost always + tell you exactly where the error is. So when debugging it, enter the + editor and find the line in question. If the problem is with a variable and + is not a typo, make sure you declared it properly. On the other hand, if + it is a typo, simply fix it! + + One thing to beware of, however, is that this error will sometimes be + reported in conjunction with a missing parentheses, brackets, or braces + type error. In these situations, your problem with an unknown identifier + is often bogus. The driver misreads the way the {} or whatever are + setup, and thus gets variable declarations confused. Therefore make + sure all other compile time errors are corrected before bothering with + these types of errors. + + In the same class with the above error, is the general syntax error. The + driver generates this error when it simply fails to understand what you + said. Again, this is often caused by typos, but can also be caused by not + properly understanding the syntax of a certain feature like writing a for() + statement: for(x=0, x<10, x++). If you get an error like this which is + not a syntax error, try reviewing the syntax of the statement in which the + error is occurring. + + 7.3 Debugging Run Time Errors + Run time errors are much more complex than their compile time + counterparts. Fortunately these errors do get logged, though many + creators do not realise or they do not know where to look. The error log + for run time errors are also generally much more detailed than compile + time errors, meaning that you can trace the history of the execution train + from where it started to where it went wrong. You therefore can setup + debugging traps using precompiler statements much easier using these + logs. Run time errors, however, tend to result from using more + complex codign techniques than beginners tend to use, which means you + are left with errors which are generally more complicated than simple + compile time errors. + + Run time errors almost always result from misusing LPC data types. + Most commonly, trying to do call others using object variables which are + NULL, indexing on mapping, array, or string variables which are + NULL, or passing bad arguments to functions. We will look at a real + run time error log from Nightmare: + + Bad argument 1 to explode() + program: bin/system/_grep.c, object: bin/system/_grep + line 32 + ' cmd_hook' in ' std/living.c' (' + std/user#4002')line 83 + ' cmd_grep' in ' bin/system/_grep.c' (' + bin/system/_grep')line 32 + Bad argument 2 to message() + program: adm/obj/simul_efun.c, object: adm/obj/simul_efun + line 34 + ' cmd_hook' in ' std/living.c' (' + std/user#4957')line 83 + ' cmd_look' in ' bin/mortal/_look.c' (' + bin/mortal/_look')line 23 + ' examine_object' in ' bin/mortal/_look.c' (' + bin/mortal/_look')line 78 + ' write' in 'adm/obj/simul_efun.c' (' + adm/obj/simul_efun')line 34 + Bad argument 1 to call_other() + program: bin/system/_clone.c, object: bin/system/_clone + line 25 + ' cmd_hook' in ' std/living.c' (' + std/user#3734')line 83 + ' cmd_clone' in ' bin/system/_clone.c' (' + bin/system/_clone')line 25 + Illegal index + program: std/monster.c, object: + wizards/zaknaifen/spy#7205 line 76 + ' heart_beat' in ' std/monster.c' + ('wizards/zaknaifen/spy#7205')line + 76 + + All of the errors, except the last one, involve passing a bad argument to a + function. The first bug, involves passing a bad first arument to the efun + explode(). This efun expects a string as its first argment. In debugging + these kinds of errors, we would therefore go to line 32 in + /bin/system/_grep.c and check to see what the data type of the first + argument being passed in fact is. In this particular case, the value being + passed should be a string. + + If for some reason I has actually passed something else, I would be done + debugging at that point and fix it simply by making sure that I was + passing a string. This situation is more complex. I now need to trace + the actual values contained by the variable being passed to explode, so + that I can see what it is the explode() efun sees that it is being passed. + + The line is question is this: + borg[files[i]] = regexp(explode(read_file(files[i]), "\n"), exp); + where files is an array for strings, i is an integer, and borg is a mapping. + So clearly we need to find out what the value of read_file(files[i]) is. + Well, this efun returns a string unless the file in question does not exist, + the object in question does not have read access to the file in question, or + the file in question is an empty file, in which cases the function will + return NULL. Clearly, our problem is that one of these events must + have happened. In order to see which, we need to look at files[i]. + + Examining the code, the files array gets its value through the get_dir() + efun. This returns all the files in a directory if the object has read access + to the directory. Therefore the problem is neither lack of access or non- + existent files. The file which caused this error then must have been an + empty file. And, in fact, that is exactly what caused this error. To + debug that, we would pass files through the filter() efun and make + sure that only files with a file size greater than 0 were allowed into the + array. + + The key to debugging a run time error is therefore knowing exactly what + the values of all variables in question are at the exact moment where the + bug created. When reading your run time log, be careful to separate the + object from the file in which the bug occurred. For example, the + indexing error above came about in the object /wizards/zaknaifen/spy, + but the error occured while running a function in /std/monster.c, which + the object inherited. + + 7.4 Malfunctioning Code + The nastiest problem to deal with is when your code does not behave the + way you intended it to behave. The object loads fine, and it produces no + run time errors, but things simply do not happen the way they should. + Since the driver does not see a problem with this type of code, no logs + are produced. You therefore need to go through the code line by line + and figure out what is happening. + + Step 1: Locate the last line of code you knew successfully executed + Step 2: Locate the first line of code where you know things are going + wrong + Step 3: Examine the flow of the code from the known successful point to + the first known unsuccessful point. + + More often than not, these problems occurr when you are using if() + statements and not accounting for all possibilities. For example: + + int cmd(string tmp) { + if(stringp(tmp)) return do_a() + else if(intp(tmp)) return do_b() + return 1; + } + + In this code, we find that it compiles and runs fine. Problem is nothing + happens when it is executed. We know for sure that the cmd() function + is getting executed, so we can start there. We also know that a value of + 1 is in fact being returned, since we do not see "What?" when we enter + the command. Immediately, we can see that for some reason the + variable tmp has a value other than string or int. As it turns out, we + issued the command without parameters, so tmp was NULL and failed + all tests. + + The above example is rather simplistic, bordering on silly. + Nevertheless, it gives you an idea of how to examine the flow of the + code when debugging malfunctioning code. Other tools are available as + well to help in debugging code. The most important tool is the use of + the precompiler to debug code. With the code above, we have a clause + checking for integers being passed to cmd(). When we type "cmd 10", + we are expecting do_b() to execute. We need to see what the value of + tmp is before we get into the loop: + + #define DEBUG + int cmd(string tmp) { + #ifdef DEBUG + write(tmp); + #endif + if(stringp(tmp)) return do_a(); + else if(intp(tmp)) return do_b(); + else return 1; + } + + We find out immediately upon issuing the command, that tmp has a + value of "10". Looking back at the code, we slap ourselves silly, + forgetting that we have to change command arguments to integers using + sscanf() before evaluating them as integers. + + 7.5 Summary + The key to debugging any LPC problem is always being aware of what + the values of your variables are at any given step in your code. LPC + execution reduces on the simplest level to changes in variable values, so + bad values are what causes bad things to happen once code has been + loaded into memory. If you get errors about bad arguments to + functions, more likely than not you are passing a NULL value to a + function for that argument. This happens most often with objects, since + people will do one of the following: + 1) use a value that was set to an object that has since destructed + 2) use the return value of this_player() when there is no this_player() + 3) use the return value of this_object() just after this_object() was + destructed + + In addition, people will often run into errors involving illegal indexing or + indexing on illegal types. Most often, this is because the mapping or + array in question was not initialized, and therefore cannot be indexed. + The key is to know exactly what the full value of the array or mapping + should be at the point in question. In addition, watch for using index + numbers larger than the size of given arrays + + Finally, make use of the precompiler to temporarly throw out code, or + introduce code which will show you the values of variables. The + precompiler makes it easy to get rid of debugging code quickly once you + are done. You can simply remove the DEBUG define when you are + done. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/lpc/types/array.2d ds2.1/lib/doc/lpc/types/array.2d *** ds1.1/lib/doc/lpc/types/array.2d Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/types/array.2d Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,33 ---- + 2D arrays can be done in LPC, quite simply. Just treat them as an array of + arrays. For example, + + a = allocate(10); + a[0] = allocate(10); + a[1] = allocate(10); + ...etc... + + Then you can reference array 0, element 0, via + + a[0][0] + + You can't declare an array of more than 1 dimension (using the type * + notation, if you have type checking on), but you can have an array of more + than one dimension. If you have type checking on, you will probably have + to declare them as type mixed. + + This also works: + + mixed a; + a = ({ ({ 1, 2, 3 }), ({ 1, 2, 3 }) }); + + In the above example, a[0] would be ({ 1, 2, 3 }), and a[0][2] would be 3. + + Or this: + + mixed a; + a = ({ 0, 0, 0, 0 }); /* just to get the array to size 4 */ + a[0] = ({ 1, 2, 3 }); + a[1] = ({ 1, 2, 3 }); + ...etc... + + John Price a.k.a. Raistlin diff -c -r --new-file ds1.1/lib/doc/lpc/types/buffer ds2.1/lib/doc/lpc/types/buffer *** ds1.1/lib/doc/lpc/types/buffer Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/types/buffer Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,11 ---- + 'buffer' is a cross between the LPC array type and the LPC string type. + 'buffer' is intended as a way to conveniently manipulate binary data. + 'buffer' is not zero-terminated (that is, it has an associated length). A + 'buffer' is an array of bytes that is implemented using one byte per + element. buf[i] = x and x = buf[i] are allowed and do work. sizeof(buf) + works. bufferp(buf) is available. buf[i..j] should work as well. buff = + read_buffer(file_name, ...) (same args as read_bytes). also 'int + write_buffer(string file, int start, mixed source)', buf = buf1 + buf2; + buf += buf1, buf = allocate_buffer(size). The socket efuns have been + modified to accept and return the 'buffer' type. (STREAM_BINARY (3) and + DATAGRAM_BINARY (4) modes.) diff -c -r --new-file ds1.1/lib/doc/lpc/types/float ds2.1/lib/doc/lpc/types/float *** ds1.1/lib/doc/lpc/types/float Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/types/float Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,13 ---- + MudOS LPC now provides support for the floating point type. Declare + variables like this: + + float pi; + + In general the same operations are supported for floats as are for integers. + Floating point constants may contain decimal points e.g. + + pi = 3.14159265; + + The LPC float type is based on the single precision floating point type + provided by C. On most machines this will give about seven (7) digits + of precision (in base 10). diff -c -r --new-file ds1.1/lib/doc/lpc/types/function ds2.1/lib/doc/lpc/types/function *** ds1.1/lib/doc/lpc/types/function Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/types/function Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,30 ---- + MudOS has a variable type named 'function'. Variables of this type may + be used to point to (object, function) pairs. Here is an example usage: + + void + test(string arg) + { + write(arg + "\n"); + } + + void + create() + { + function f; + + f = (: this_object(), "test" :); + (*f)("hello, world!"); + write("functionp(f) == " + functionp(f) + "\n"); + } + + Note, (*f)(args) is internally translated to obj->func(args) where + f == (: obj, func :). In (: obj, func :), obj and func may be any + type allowed by call_other(obj, func). + + (: "hi" :) makes a function pair that is equivalent to (: this_object(), "hi" :) + + Note that: + + f is the same as (: f[0], f[1] :) + + Author: Truilkan, December 1992 diff -c -r --new-file ds1.1/lib/doc/lpc/types/general ds2.1/lib/doc/lpc/types/general *** ds1.1/lib/doc/lpc/types/general Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/types/general Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,131 ---- + Types can be used in four places: + + Declaring type of global variables. + Declaring type of functions. + Declaring type of arguments to functions. + Declaring type of local variables in functions. + + Normally, the type information is completely ignored, and can be regarded + purely as documentation. However, when the basic type of a function is + declared, then a more strict type checking will be enforced inside of that + function. That means that the type of all arguments must be defined, and the + variables can only be used to store values of the declared type. The + function call_other() is defined to return an unknown type, as the compiler + has no way of knowing the return type. This value must be casted (when + strict type checking is enabled). Casting a type is done by putting the type + name inside a pair of '(' and ')'. + + An example when querying the short description of an object: + + (string)call_other(ob, "short"); + ...or... + (string)ob->short(); + + When a function is compiled with strict type testing, it can only call other + functions that are already defined. If they are not yet defined, prototypes + must be used to allow the current function to call them. + + An example of a prototype: + + string func(int arg); + + Note the ';' instead of a body to the function. All arguments must be given + by names, but do not have to have the same names as in the real definition. + All types must of course be the same. + + There are two kinds of types. Basic types, and special types. There can be + at most one basic type, but any number of special types assigned to a + variable/function. + + The strict type checking is only used by the compiler, not at runtime. So, + it is actually possible to store a number in a string variable even when + strict type checking is enabled. + + Why use strict type checking? It is really recommended, because the compiler + will find many errors at compile time, which will save a lot of hard work. It + is in general much harder to trace an error occuring at run time. + + The basic types can be divided into groups. Those that are referenced by + value, and those that are referenced by address. The types int, string, + and float are referenced by value. The types mapping, function, object, + and pointers ('<type> *') are referenced by address. If a value of this type + is assigned to a variable or passed as argument, they will all point to the + same actual data. That means that if the value of an element in an array is + changed, then it can modify all other variables pointing to the same array. + Changing the size of the array will always allocate a new one though. The + comparison operator, ==, will compare the actual value for the group of + value-referenced types above. But for arrays, mappings, etc, it will simply + check if it is the same array, mapping, etc. That has the very important + implication that the expression ({}) == ({}) will evaluate to false because + the array construction operator-pair, ({}) always generates a new array. + + Basic types + + int + An integer number (32 bit). + + float + A floating point number (32 bit). + + string + An unlimited string of characters. + + object + A pointer to an object. + + mapping + A form of associative array, see separate documentation. + + function + A special type that points to (object, function name) pairs, see + separate documentation. + + Arrays + Arrays are declared using a '*' following a basic type. For example, + declaring an array of numbers: int *arr;. Use the type mixed if you want an + array of arrays, or a mixed combination of types. + + void + This type is only usable for functions. It means that the function will not + return any value. The compiler will complain (when type checking is enabled) + if a return value is used. + + mixed + This type is special, in that it is valid to use in any context. Thus, if + everything was declared mixed, then the compiler would never complain. This + is of course not the idea. It is really only supposed to be used when a + variable really is going to contain different types of values. This should + be avoided if possible. It is not good coding practice to allow a function, + for example, to return different types. + + Special types + + There are some special types, which can be given before the basic type. These + special types can also be combined. When using special type T before an + inherit statement, all symbols defined by inheritance will also get the + special type T. The only special case is public--defined symbols, which can + not be redefined as private in a private inheritance statement. + + varargs + A function of this type can be called with a variable number of arguments. + Otherwise, the number of arguments is checked, and can generate an error. + + private + Can be given for both functions and variables. Functions that are private in + object A can not be called through call_other() in another object. They're + also not accessable to any object that inherits A. + + static + This special type behaves different for variables and functions. It is + similar to private for functions, in that they cannot be called from other + objects with call_other(). static variables will be neither saved nor + restored when using save_object() or restore_object(). + + public + A function defined as public will always be accessible from other objects, + even if private inheritance is used. + + nomask + All symbols defined as nomask cannot be redefined by inheritance. They can + still be used and accessed as usual. nomask also blocks functions from + being shadowed with shadow(). diff -c -r --new-file ds1.1/lib/doc/lpc/types/mappings ds2.1/lib/doc/lpc/types/mappings *** ds1.1/lib/doc/lpc/types/mappings Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/lpc/types/mappings Wed Jul 5 00:01:11 2006 *************** *** 0 **** --- 1,170 ---- + Mappings usage 1992 September 28 + + Documentation on MudOS's mapping datatype - written by Truilkan@TMI: + + MudOS 0.9 provides a datatype calling the 'mapping'. Mappings are + the equivalent of associative arrays found in other languages (e.g. Perl). + An associative array is similar to a regular array except that associative + arrays can be indexed by any type of data (string, object, int, array, etc) + rather than just integers. In addition, associative arrays are sparse arrays + which means you can have a mapping which has a value for its 1,000,000th + element without having values for any other elements. Two particularly + effective uses for mappings are: 1) databases, and 2) a substitute for the + aggregate type 'struct' (as used in the C language) by representing each + field of the C struct as a key in the mapping. + + A mapping is declared like this: + + mapping x; + + A mapping can be initialized in one of two ways: + + x = ([key0 : value0, key1 : value1, ...]); + + (note: 'x = ([]);' can be used to create an empty mapping) + + Note that a mapping _must_ be initialized before you may assign any elements + to it. This restriction exists because of the way the gamedriver + initializes all variables (regardless of type) to zero (0). If you do not + initialize the mapping, then you'll see an "Indexing on illegal type" error + when you try to assign an element to the mapping. + + New (key, value) pairs may be added to the map in the following way: + + x[key] = value; + + The above statement causes the driver to search the mapping named 'x' for the + specified key. If the mapping contains that key, then the associated value + (in the mapping) is replaced with the value on the right hand side of the + assignment. If the mapping does not already contain that key, then + additional space is automatically allocated (dynamically) and the + (key, value) pair is inserted into the mapping. + + An element of a mapping may be referenced as follows: + + write(x[key] + "\n"); + + An element of a mapping may be deleted as follows: + + map_delete(x, key); + + this deletion will cause the following expression to evaluate to true (1): + + undefinedp(x[key]) + + so that you could write code such as this: + + if (undefinedp(value = x["MudOS"])) { + write("'MudOS' is not used as a key in the mapping 'x'\n"); + } else { + write("the value for the key 'MudOS' is " + value + "\n"); + } + + A list of the keys (indices) may be obtained using the keys() efun, for + example: + + mixed *idx; + map x; + + x = ([ "x" : 3, "y" : 4]); + idx = keys(x); /* idx == ({"x", "y"}) or ({"y", "x"}) */ + + Note that keys() will return the list of indices in an apparently random + order (the order is a side effect of the implementation used to store + the mapping -- in this case, an extensible hash table). + + A list of the values in a mapping may be obtained using the values() + efun, for example: + + idx = values(x); + + causes idx to be equal to ({3, 4}) or ({4, 3}). Note that values() will + return the values in the same order as keys() returns the corresponding + keys. + + The (key, value) pairs in a mapping may be iterated over using the each() + efun. each() returns a null vector when the end of the mapping is reached. + each() returns the (key, value) pairs in the same order as keys() and values() + do. For example: + + mixed *pair; + + while ((pair = each(x)) != ({})) { + write("key = " + pair[0] + "\n"); + write("value = " + pair[1] + "\n"); + } + + Mappings can be two-dimensional (or n-dimensional for that matter) in the same + sense that LPC arrays can be. + + mapping x, y; + + x = ([]); + y = ([]); + + y["a"] = "c"; + x["b"] = y; + + And then x["b"]["a"] == "c" + + Mappings can also be composed using the '*' operator (composed in the + mathematical sense of the word): + + mapping r1, r2, a; + + r1 = ([]); + r2 = ([]); + + r1["driver"] = "mudlib"; + r2["mudlib"] = "castle"; + + so: + + a = r1 * r2 + + defines a to be a map with: a["driver"] == "castle"; + + You may also add two mappings. The sum of two mappings is defined + as the union of the two mappings. + + a = r1 + r2 + + defines a to be a map with a["driver"] == "mudlib" and + a["mudlib"] == "castle" + + The += operator is also supported. Thus you could use: + + a += ([key : value]); + + as a substitute for: + + a[key] = value; + + However, the latter form (a[key] = value) is much more efficient since + the former (in the present implementation) involves the creation of a new + mapping while the latter does not. + + The subtraction operator is not defined for mappings (use map_delete()). + + The sizeof() efun may be used to determine how many (key, value) pairs + are in the mapping. For example, + + write("The mapping 'x' contains " + sizeof(x) + " elements.\n"); + + the implementation: + + MudOS's mappings are implemented using an extensible hash table. The + size of the hash table is always a power of 2. When a certain percentage + of the hash table buckets become full, the size of the hash table is + doubled in order to maintain the efficiency of accesses to the hash + table. + + credits: + + MudOS's mappings were originally implemented by Whiplash@TMI. Parts of + the implementation were later rewritten by Truilkan@TMI (to use an + extensible hash table rather than a binary tree). + + Parts of the data structure used to implement mappings are based on + the hash.c module from the Perl programming language by Larry Wall. + The Perl package is covered under the GNU Copyleft general public license. diff -c -r --new-file ds1.1/lib/doc/manual/chapter01 ds2.1/lib/doc/manual/chapter01 *** ds1.1/lib/doc/manual/chapter01 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter01 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,91 ---- + chapter 1 "Introduction to the Coding Environment" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 25 may 1993 + + CHAPTER 1: Introduction to the Coding Environment + + 1.1 UNIX file structure + LPMuds use basic UNIX commands and its file structure. If you know + UNIX commands already, then note (with a few exceptions) options are + not available to the commands. Like DOS, UNIX is heirarchical. The + root directory of which all directories are sub-directories is called + root(/). And from those sub-directories you may have further + sub-directories. A directory may be referred to in two different ways: + 1) by its full name, or absolute name, or 2) by its relative name. + Absolute name refers to the directory's full path starting from / winding + down the directory tree until you name the directory in question. For + example: + + /players/descartes/obj/monster + + refers to the directory monster which is a sub-directory of obj which + is a sub-directory of descartes which is a sub-directory of players + which is a sudirectory of /. + + The relative name refers to the name relative to another directory. + The above example is called monster relative to /players/descartes/obj, + but it is also called obj/monster relative to /players/descartes, + descartes/obj/monster relative to /players, and finally + players/descartes/obj/monster relative to /. You can tell the + difference between absolute names and relative names because absolute + names always start with /. In order to know exactly which directory + is being named by a relative name, you naturally must know what + directory it is relative to. + + A directory contains sub-directories and files. LPMuds only use text files + inside the mudlib. Like directories, files have both absolute and + relative names. The most basic relative name is often referred to as the file + name, with the rest of the absolute name being referred to as the path. So, + for the file: /players/descartes/castle.c, castle.c is the file name, and + /players/descartes is the path. + + On some muds, a file with a file name beginning with a . (like .plan) is + not visible when you list files with the regular file listing command. + + 1.2 UNIX Commands + Along with the UNIX file structure, LPMuds use many UNIX commands. Typical + UNIX commands on most muds are: + pwd, cd, ls, rm, mv, cp, mkdir, rmdir, more, head, cat, ed + If you have never before seen UNIX commands, you probably are thinking this + is all nonsense. Well, it is, but you got to use them. Before getting + into what they mean though, first a discussion of current directory. + If you know DOS, then you know what a current working directory is. + At any given point, you are considered to be "in" some directory. This + means that any relative file or directory names you give in UNIX commands + are relative to that directory. For example, if my current directory is + /players/descartes and I type "ed castle.c" (ed is the command to edit), + then it assumes I mean the file /players/descartes/castle.c + + pwd: shows you your current working directory + cd: changes your current working directory. You may give either relative + or absolute path names. With no arguments, it changes to your home + directory. + ls: lists all files in the directory named. If no directory is named, + it lists the files of the current working directory + rm: deletes the file named + mv: renames the file named + cp: copies the file named + mkdir: makes a new directory + rmdir: deletes a directory. All files must have been first removed. + more: pages the file named so that the file appears on your screen one + page at a time. + cat: shows the whole file to you at once + head: shows you the first several lines of a file + tail: shows you the last several lines of a file + ed: allows you to edit a file using the mud editor + + 1.3 Chapter Summary + UNIX uses a heirarchical file structure with the root of the tree being + named /. Other directories branch off from that root directory and + in turn have their own sub-directories. All directories may contain + directories and files. Directories and files are referred to either + by their absolute name, which always begins with /, or by their relative + name which gives the file's name relative to a particular directory. + In order to get around in the UNIX files structure, you have the + typical UNIX commands for listing files, your current directory, etc. + On your mud, all of the above commands should have detailed help commands + to help you explore exactly what they do. In addition, there should + be a very detailed file on your mud's editor. If you are unfamiliar + with ed, you should go over this convoluted file. diff -c -r --new-file ds1.1/lib/doc/manual/chapter02 ds2.1/lib/doc/manual/chapter02 *** ds1.1/lib/doc/manual/chapter02 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter02 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,196 ---- + chapter 2 "The LPC Program" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 16 june 1993 + + CHAPTER 2: The LPC Program + + 2.1 About programs + The title of this chapter of the textbook is actually poorly named, since + one does not write programs in LPC. An LPC coder instead writes *objects*. + What is the difference? Well, for our purposes now, the difference is + in the way the file is executed. When you "run" a program, execution + begins at a definite place in the program. In other words, there + is a place in all programs that is noted as the beginning where program + execution starts. In addition, programs have definite end points, + so that when execution reaches that point, the execution of the program + terminates. So, in short, execution of a program runs from a definite + beginning point through to a definite end point. This is not so with + LPC objects. + + With muds, LPC objects are simply distinct parts of the C program which + is running the game (the driver). In other words, execution of the mud + program begins and ends in the driver. But the driver in fact does + very little in the way of creating the world you know when you play + a mud. Instead, the driver relies heavily on the code created in LPC, + executing lines of the objects in the mud as needed. LPC objects thus + have no place that is necessarily the beginning point, nor do they + have a definite ending point. + + Like other programming languages, an LPC "program" may be made up of + one or more files. For an LPC object to get executed, it simple + needs to be loaded into the driver's memory. The driver will call lines + from the object as it needs according to a structure which will be + defined throughout this textbook. The important thing you need to + understand at this point is that there is no "beginning" to an LPC + object in terms of execution, and there is no "end". + + 2.2 Driver-mudlib interaction + As I have mentioned earlier, the driver is the C program that runs on + the host machine. It connects you into the game and processes LPC code. + Note that this is one theory of mud programming, and not necessarily + better than others. It could be that the entire game is written in C. + Such a game would be much faster, but it would be less flexible in + that wizards could not add things to the game while it was running. This + is the theory behind DikuMUDs. Instead, LPMUDs run on the theory that + the driver should in no define the nature of the game, that the nature + of the game is to be decided by the individuals involved, and that + you should be able to add to the game *as it is being played*. This + is why LPMUDs make use of the LPC programming language. It allows + you to define the nature of the game in LPC for the driver to read and + execute as needed. It is also a much simpler language to understand + than C, thus making the process of world creation open to a greater + number of people. + + Once you have written a file in LPC (assuming it is corrent LPC ), it justs + sits there on the host machine's hard drive until something in the game + makes reference to it. When something in the game finally does make + reference to the object, a copy of the file is loaded into memory and + a special *function* of that object is called in order to initialize + the values of the variables in the object. Now, do not be concerned + if that last sentence went right over your head, since someone brand + new to programming would not know what the hell a function or a variable + is. The important thing to understand right now is that a copy of the + object file is taken by the driver from the machine's hard drive and + stored into memory (since it is a copy, multiple versions of that + object may exist). You will later understand what a function is, what + a variable is, and exactly how it is something in the game made reference + to your object. + + 2.3 Loading an object into memory + Although there is no particular place in an object code that must exist + in order for the driver to begin executing it, there is a place for which + the driver will search in order to initialize the object. On compat + drivers, it is the function called reset(). On native muds it is the + function called create(). + + LPC objects are made up of variables (values which can change) and + functions which are used to manipulate those variables. Functions + manipulate variables through the use of LPC grammatical structures, + which include calling other functions, using externally defined + functions (efuns), and basic LPC expressions and flow control + mechanisms. + + Does that sound convoluted? First lets start with a variable. A + variable might be something like: level. It can "vary" from sitation + to situation in value, and different things use the value of the player's + level to make different things happen. For instance, if you are a + level 19 player, the value of the variable level will be 19. Now + if your mud is on the old LPMud 2.4.5 system where levels 1-19 are + players and 20+ are wizards, things can ask for your level value to + see if you can perform wizard type actions. Basically, each object + in LPC is a pile of variables with values which change over time. + Things happen to these objects based on what values its variables + hold. Often, then things that happen cause the variables to change. + + So, whenever an object in LPC is referenced by another object currently + in memory, the driver searches to see what places for values the + object has (but they have no values yet). Once that is done, the driver + calls a function in the object called reset() or create() (depending + on your driver) which will set up the starting values for the object's + variables. It is thus through *calls* to *functions* that variable + values get manipulated. + + But create() or reset() is NOT the starting place of LPC code, although + it is where most LPC code execution does begin. The fact is, those + functions need not exist. If your object does just fine with its + starting values all being NULL pointers (meaning, for our purposes + here, 0), then you do not need a create() or reset() function. Thus + the first bit of execution of the object's code may begin somewhere + completely different. + + Now we get to what this chapter is all about. The question: What + consists a complete LPC object? Well, an LPC object is simply + one or more functions grouped together manipulating 0 or more + variables. The order in which functions are placed in an object + relative to one another is irrelevant. In other words: + + ----- + void init() { add_action("smile", "smile"); } + + void create() { return; } + + int smile(string str) { return 0; } + ----- + + is exactly the same as: + + ----- + void create() { return; } + + int smile(string str) { return 0; } + + void init() { add_action("smile", "smile"); } + _____ + + Also important to note, the object containing only: + + ----- + void nonsense() {} + ----- + + is a valid, but trivial object, although it probably would not interact + properly with other objects on your mud since such an object has no + weight, is invisible, etc.. + + 2.4 Chapter summary + LPC code has no beginning point or ending point, since LPC code is used + to create objects to be used by the driver program rather than create + individual programs. LPC objects consist of one or more functions whose + order in the code is irrelevant, as well as of zero or more variables whose + values are manipulated inside those functions. LPC objects simply sit + on the host machine's hard driver until referenced by another object in + the game (in other words, they do not really exist). Once the object + is referenced, it is loaded into the machine's memory with empty + values for the variables. The function reset() in compat muds or + create() in native muds is called in that object if it exists to allow + the variables to take on initial values. Other functions in the object + are used by the driver and other objects in the game to allow interaction + among objects and the manipulation of the LPC variables. + + A note on reset() and create(): + create() is only used by muds in native mode (see the textbook Introduction + for more information on native mode vs. compat mode). It is only used + to initialize newly referenced objects. + + reset() is used by both muds in compat mode and native mode. In compat + mode, reset() performs two functions. First, it is used to initialize + newly referenced objects. In addition, however, compat mode muds use + reset() to "reset" the object. In other words, return it to its initial + state of affairs. This allows monsters to regenerate in a room and doors + to start back in the shut position, etc.. Native mode muds use reset() + to perform the second function (as its name implies). + + So there are two important things which happen in LP style muds which + cause the driver to make calls to functions in objects. The first is + the creation of the object. At this time, the driver calls a function + to initalize the values in the object. For compat mode muds, this + is performed by the function named reset() (with an argument of 0, + more on this later though). For muds running in native mode, this is + performed by the function create(). + + The second is the returning of the room to some base state of affairs. + This base set of affairs may or may not be different from the initial + state of affairs, and certainly you would not want to take up time + doing redundant things (like resetting variables that never change). + Compat mode muds nevertheless use the same function that was used to + create the object to reset it, that being reset(). Native mode muds, + who use create() to create the room, instead use reset() to reset it. + All is not lost in compat mode though, as there is a way to tell the + difference between creation and resetting. For reset purposes, the + driver passes either 1 or the reset number as an argument to reset() + in compat mode. Now this is meaningless to you now, but just keep in + mind that you can in fact tell the difference in compat mode. Also + keep in mind that the argment in the creation use of reset is 0 and + the argument in the reset use is a nonzero number. diff -c -r --new-file ds1.1/lib/doc/manual/chapter03 ds2.1/lib/doc/manual/chapter03 *** ds1.1/lib/doc/manual/chapter03 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter03 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,186 ---- + chapter 3 "LPC Data Types" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 17 june 1993 + + CHAPTER 3: LPC Data Types + + 3.1 What you should know by now + LPC object are made up of zero or more variables manipulated by one or + more functions. The order in which these functions appear in code is + irrelevant. The driver uses the LPC code you write by loading copies of + it into memory whenever it is first referenced and additional copies + through cloning. When each object is loaded into memory, all the variables + initially point to no value. The reset() function in compat muds, and + create() in native muds are used to give initial values to variables in + objects. The function for creation is called immediately after the object + is loaded into memory. However, if you are reading this textbook with no + prior programming experience, you may not know what a function is or how + it gets called. And even if you have programming experience, you may + be wondering how the process of functions calling each other gets started + in newly created objects. Before any of these questions get answered, + however, you need to know more about what it is the functions are + manipulating. You therefore should thouroughly come to know the concept + behind LPC data types. Certainly the most boring subject in this manual, + yet it is the most crucial, as 90% of all errors (excepting misplaced + {} and ()) involve the improper usage of LPC data types. So bear through + this important chapter, because it is my feeling that understanding this + chapter alone can help you find coding much, much easier. + + 3.2 Communicating with the computer + You possibly already know that computers cannot understand the letters + and numbers used by humans. Instead, the "language" spoken by computers + consists of an "alphabet" of 0's and 1's. Certainly you know computers + do not understand natural human languages. But in fact, they do not + understand the computer languages we write for them either. Computer + languages like BASIC, C, C++, Pascal, etc. are all intermediate + languages. They allow you to structure your thoughts more coherently + for translation into the 0's and 1's of the computer's languages. + + There are two methods in which translation is done: compilation and + interpretation. These simply are differences betweem when the + programming language is translated into computer language. With + compiled languages, the programmer writes the code then uses a program + called a compiler to translate the program into the computer's + language. This translation occurs before the program is run. With + interpreted languages however, the process of translation occurs as + the program is being run. Since the translation of the program is + occurring during the time of the program's running in interpreted + languages, interpreted languages make much slower programs than + compiled languages. + + The bottom line is, no matter what language you are writing in, at + some point this has to be changed into 0's and 1's which can be + understood by the computer. But the variables which you store in + memory are not simply 0's and 1's. So you have to have a way in + your programming languages of telling the computer whether or not + the 0's and 1's should be treated as decimal numbers or characters or + strings or anything else. You do this through the use of data types. + + For example, say you have a variable which you call 'x' and you give + it the decimal whole number value 65. In LPC you would do this through + the statement: + + ----- + x = 65; + ----- + + You can later do things like: + + _____ + write(x+"\n"); /* \n is symbolically represents a carriage return */ + y = x + 5; + ----- + + The first line allows you to send 65 and a carriage return to someone's screen. + The second line lets you set the value of y to 70. + The problem for the computer is that it does not know what '65' means when + you tell it x = 65;. What you think of 65, it might think of as: + 00000000000000000000000001000001 + But, also, to the computer, the letter 'A' is represented as: + 00000000000000000000000001000001 + So, whenever you instruct the computer write(x+"\n");, it must have some + way of knowing that you want to see '65' and not 'A'. + + The computer can tell the difference between '65' and 'A' through the use + of data types. A data types simply says what type of data is being stored + by the memory location pointed to by a given variable. Thus, each LPC + variable has a variable type which guides conversions. In the example + given above, you would have had the following line somewhere in the + code *before* the lines shown above: + + ----- + int x; + ----- + + This one line tells the driver that whatever value x points to, it will + be used as the data type "int", which is short for integer, or whole + number. So you have a basic introduction into the reason why data types + exist. They exist so the driver can make sense of the 0's and 1's that + the computer is storing in memory. + + 3.3 The data types of LPC + All LPMud drivers have the following data types: + + void, status, int, string, object, int *, string *, object *, mixed * + + Many drivers, but not all have the following important data types which + are important to discuss: + + float, mapping, float *, mapping * + + And there are a few drivers with the following rarely used data types + which are not important to discuss: + + function, enum, struct, char + + 3.4 Simple data types + This introductory textbook will deal with the data types void, status, + int, float, string, object, mand mixed. You can find out about the + more complex data types like mappings and arrays in the intermediate + textbook. This chapter deals with the two simplest data types (from the + point of view of the LPC coder), int and string. + + An int is any whole number. Thus 1, 42, -17, 0, -10000023 are all type int. + A string is one or more alphanumeric characters. Thus "a", "we are borg", + "42", "This is a string" are all strings. Note that strings are always + enclosed in "" to allow the driver to distinguish between the int 42 and + the string "42" as well as to distinguish between variable names (like x) + and strings by the same names (like "x"). + + When you use a variable in code, you must first let the driver know + what type of data to which that variable points. This process is + called *declaration*. You do this at the beginning of the function + or at the beginning of the object code (outside of functions before all + functions which use it). This is done by placing the name of the data type + before the name of the variable like in the following example: + + ----- + void add_two_and_two() { + int x; + int y; + + x = 2; + y = x + x; + } + ----- + + Now, this is a complete function. The name of the function is + add_two_and_two(). The function begins with the declaration of an + int variable named x followed by the declaration of an in variable + named y. So now, at this point, the driver now has two variables which + point to NULL values, and it expects what ever values end up there to be + of type int. + + A note about the data types void and status: + Void is a trivial data type which points to nothing. It is not used + with respect to variables, but instead with respect to functions. You + will come to understand this better later. For now, you need only + understand that it points to no value. + + The data type status is a boolean data type. That is, it can only have + 1 or 0 as a value. This is often referred to as being true or false. + + 3.5 Chapter summary + For variables, the driver needs to know how the 0's and 1's the computer + stores in memory get converted into the forms in which you intend them + to be used. The simplest LPC data types are void, status, int, and string. + You do not user variables of type void, but the data type does come + into play with respect to functions. In addition to being used for + translation from one form to the next, data types are used in determining + what rules the driver uses for such operations as +, -, etc. For example, + in the expression 5+5, the driver knows to add the values of 5 and 5 + together to make 10. With strings however, the rules for int addition + make no sense. So instead, with "a"+"b", it appends "b" to the string "a" + so that the final string is "ab". Errors can thus result if you mistakenly + try to add "5"+5. Since int addition makes no sense with strings, the + driver will convert the second 5 to "5" and use string addition. The final + result would be "55". If you were looking for 10, you would therefore + have ended up with erroneous code. Keep in mind, however, that in most + instances, the driver will not do something so useful as coming up with + "55". It comes up with "55" cause it has a rule for adding a string + to an int, namely to treat the int as a string. In most cases, if you + use a data type for which an operation or function is not defined + (like if you tried to divide "this is" by "nonsense", "this is"/"nonsense"), + the driver will barf and report an error to you. diff -c -r --new-file ds1.1/lib/doc/manual/chapter04 ds2.1/lib/doc/manual/chapter04 *** ds1.1/lib/doc/manual/chapter04 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter04 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,226 ---- + chapter 4 "Functions" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 22 june 1993 + + CHAPTER 4: Functions + + 4.1 Review + By this point, you should be aware that LPC objects consist of functions + which manipulate variables. The functions manipulate variables when they + are executed, and they get executed through *calls* to those functions. + The order in which the functions are placed in a file does not matter. + Inside a function, the variables get manipulated. They are stored in + computer memory and used by the computer as 0's and 1's which + get translated to and from useable output and input through a device + called data typing. String data types tell the driver that the + data should appear to you and come from you in the form of alphanumeric + characters. Variables of type int are represented to you as whole + number values. Type status is represented to you as either 1 or 0. + And finally type void has no value to you or the machine, and is not + really used with variable data types. + + 4.2 What is a function? + Like math functions, LPC functions take input and return output. + Languages like Pascal distinguish between the concept of proceedure abd + the concept of function. LPC does not, however, it is useful to + understand this distinction. What Pascal calls a proceedure, LPC + calls a function of type void. In other words, a proceedure, or function + of type void returns no output. What Pascal calls a function differs + in that it does return output. In LPC, the most trivial, correct + function is: + + ----- + void do_nothing() { } + ----- + + This function accepts no input, performs no instructions, and returns no + value. + + There are three parts to every properly written LPC function: + 1) The declaration + 2) The definition + 3) The call + + Like with variables, functions must be declared. This will allow the + driver to know 1) what type of data the function is returning as output, + and 2) how many input(s) and of what type those input(s) are. The + more common word for input is parameters. + A function declaration therefore consists of: + type name(parameter1, parameter2, ..., parameterN); + The declaration of a function called drink_water() which accepts a string as + input and an int as output would thus look like this: + + ----- + int drink_water(string str); + ----- + + where str is the name of the input as it will be used inside the function. + + The function definition is the code which describes what the function actually + does with the input sent to it. + The call is any place in other functions which invokes the execution of the + function in question. For two functions write_vals() and add(), you thus + might have the following bit of code: + + ----- + /* First, function declarations. They usually appear at the beginning + of object code. + */ + void write_vals(); + int add(int x, int y); + + /* Next, the definition of the function write_vals(). We assume that + this function is going to be called from outside the object + */ + void write_vals() { + int x; + + /*N Now we assign x the value of the output of add() through a call */ + x = add(2, 2); + write(x+"\n"); + } + + /* Finally, the definition of add() */ + int add(int x, int y) { + return (x + y); + } + ----- + + Remember, it does not matter which function definition appears first in the + code. This is because functions are not executed consecutively. Instead, + functions are executed as called. The only requirement is that the + declaration of a function appear before its definition and before the + definition of any function which makes a call to it. + + 4.3 Efuns + Perhaps you have heard people refer to efuns. They are externally defined + functions. Namely, they are defined by the mud driver. If you have + played around at all with coding in LPC, you have probably found some + expressions you were told to use like this_player(), write(), say(), + this_object(), etc. look a lot like functions. That is because they are + efuns. The value of efuns is that they are much faster than LPC functions, + since they already exist in the binary form the computer understands. + + In the function write_vals() above, two functions calls were made. The first was to + the functions add(), which you declared and defined. The second call, however, + was to a function called write(), and efun. The driver has already declared + and defined this function for you. You needs only to make calls to it. + + Efuns are created to hanldle common, every day function calls, to handle + input/output to the internet sockets, and other matters difficult to be + dealt with in LPC. They are written in C in the game driver and compiled + along with the driver before the mud comes up, making them much faster + in execution. But for your purposes, efun calls are just like calls + made to your functions. Still, it is important to know two things of any + efun: 1) what return type does it have, and 2) what parameters of what + types does it take. + + Information on efuns such as input parameters and return types is often + found in a directory called /doc/efun on your mud. I cannot + detail efuns here, because efuns vary from driver to driver. However, + you can often access this information using the commands "man" or "help" + depending on your mudlib. For instance, the command "man write" would + give you information on the write efun. But if all else fails, + "more /doc/efun/write" should work. + + By looking it up, you will find write is declared as follows: + + ----- + void write(string); + ----- + + This tells you an appropriate call to write expects no return value and + passes a single parameter of type string. + + 4.4 Defining your own functions + Although ordering your functions within the file does not matter, ordering + the code which defines a function is most important. Once a function + has been called, function code is executed in the order it appears + in the function definition. In write_vals() above, the instruction: + + ----- + x = add(2, 2); + ----- + + Must come before the write() efun call if you want to see the appropriate + value of x used in write(). + + With respect to values returned by function, this is done through the "return" + instruction followed by a value of the same data type as the function. In + add() above, the instruction is "return (x+y);", where the value of (x+y) + is the value returned to write_vals() and assigned to x. On a more + general level, "return" halts the execution of a function and returns + code execution to the function which called that function. In addition, + it returns to the calling function the value of any expression that follows. + To stop the execution of a function of type void out of order, use + "return"; without any value following. Once again, remember, the data + type of the value of any expression returned using "return" MUST be the + same as the data type of the function itself. + + 4.5 Chapter Summary + The files which define LPC objects are made of of functions. Functions, in + turn, are made up of three parts: + 1) The declaration + 2) The definition + 3) The call + Function declarations generally appear at the top of the file before any + defintions, although the requirement is that the declaration must appear + before the function definition and before the definition of any function + which calls it. + Function definitions may appear in the file in any order so long as they + come after their declaration. In addition, you may not define one function + inside another function. + Function calls appear inside the definition of other functions where you + want the code to begin execution of your function. They may also appear + within the definition of the function itself, but this is not recommended + for new coders, as it can easily lead to infinite loops. + + The function definition consists of the following in this order: + 1) function return type + 2) function name + 3) opening ( followed by a parameter list and a closing ) + 4) an opening { instructing the driver that execution begins here + 5) declarations of any variables to be used only in that function + 6) instructions, expressions, and calls to other functions as needed + 7) a closing } stating that the function code ends here and, if no + "return" instruction has been given at this point (type void functions + only), execution returns to the calling function as if a r"return" + instruction was given + + The trivial function would thus be: + + ----- + void do_nothing() {} + ----- + + since this function does not accept any input, perform any instructions, or + return any output. + + Any function which is not of type void MUST return a value of a data type + matching the function's data type. + + Each driver has a set of functions already defined for you called efuns + These you need neither need to declare nor define since it has already + been done for you. Furthermore, execution of these functions is faster + than the execution of your functions since efuns are in the driver. + In addition, each mudlib has special functions like efuns in that they + are already defined and declared for you, but different in that they + are defined in the mudlib and in LPC. They are called simul_efuns, or + simulated efuns. You can find out all about each of these as they are + listed in the /doc/efun directory on most muds. In addition many + muds have a command called "man" or a "help" command which allows you + simply to call up the info files on them. + + Note on style: + Some drivers may not require you to declare your functions, and some + may not require you to specify the return type of the function in its + definition. Regardless of this fact, you should never omit this information + for the following reasons: + 1) It is easier for other people (and you at later dates) to read your + code and understand what is meant. This is particularly useful + for debugging, where a large portion of errors (outside of misplaced + parentheses and brackets) involve problems with data types (Ever + gotten "Bad arg 1 to foo() line 32"?). + 2) It is simply considered good coding form. diff -c -r --new-file ds1.1/lib/doc/manual/chapter05 ds2.1/lib/doc/manual/chapter05 *** ds1.1/lib/doc/manual/chapter05 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter05 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,162 ---- + chapter 5 "The Basics of Inheritance" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 01 july 1993 + + CHAPTER 5: The Basics of Inheritance + + 5.1 Review + You should now understand the basic workings of functions. You should be + able to declare and call one. In addition, you should be able to recognize + function definitions, although, if this is your first experience with LPC, + it is unlikely that you will as yet be able to define your own functions. + There functions form the basic building blocks of LPC objects. Code + in them is executed when another function makes a call to them. In making + a call, input is passed from the calling function into the execution of + the called one. The called function then executes and returns a value + of a certain data type to the calling function. Functions which return + no value are of type void. + + After examining your workroom code, it might look something like this + (depending on the mudlib): + + ----- + inherit "/std/room"; + + void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + set("short", "Descartes' Workroom"); + set("long", "This is where Descartes works.\nIt is a cube.\n"); + SetExits( ({ "/domains/standard/square" }), ({ "square" }) ); + } + ----- + + If you understand the entire textbook to this point, you should recognize + of the code the following: + 1) create() is the definition of a function (hey! he did not declare it) + 2) It makes calls to SetProperty(), set(), and SetExits(), none + of which are declared or defined in the code. + 3) There is a line at the top that is no variable or function declaration + nor is it a function definition! + + This chapter will seek to answer the questions that should be in your head + at this point: + 1) Why is there no declaration of create()? + 2) Where are the functions SetProperty(), set(), and SetExits() declared + and defined? + 3) What the hell is that line at the top of the file? + + 5.2 Object oriented programming + Inheritance is one of the properties which define true object oriented + programming (OOP). It allows you to create generic code which can be used + in many different ways by many different programs. What a mudlib does is + create these generalized files (objects) which you use to make very specific + objects. + + If you had to write the code necessary for you to define the workroom above, + you would have to write about 1000 lines of code to get all the functionality + of the room above. Clearly that is a waste of disk space. In addition, + such code does not interact well with players and other rooms since every + creator is making up his or her own functions to perform the functionality + of a room. Thus, what you might use to write out the room's long description, + GetLong(), another wizard might be calling long(). This is the primary + reason mudlibs are not compatible, since they use different protocols for + object interaction. + + OOP overcomes these problems. In the above workroom, you inherit the + functions already defined in a file called "/std/room.c". It has all + the functions which are commonly needed by all rooms defined in it. When + you get to make a specific room, you are taking the general functionality + of that room file and making a unique room by adding your own function, + create(). + + 5.3 How inheritance works + As you might have guessed by now, the line: + + ----- + inherit "/std/room"; + ----- + + has you inherit the functionality of the room "/std/room.c". By inheriting + the functionality, it means that you can use the functions which have + been declared and defined in the file "/std/room.c" In the Nightmare Mudlib, + "/std/room.c" has, among other functions, SetProperty(), set(), and + SetExits() declared and defined. In your function create(), you are + making calls to those functions in order to set values you want your + room to start with. These values make your room different from others, yet + able to interact well with other objects in memory. + + In actual practice, each mudlib is different, and thus requires you to use + a different set of standard functions, often to do the same thing. It is + therefore beyond the scope of this textbook even to describe what + functions exist and what they do. If your mudlib is well documented, + however, then (probably in /doc/build) you will have tutorials on how + to use the inheritable files to create such objects. These tutorials + should tell you what functions exist, what input they take, the data + type of their output, and what they do. + + 5.4 Chapter summary + This is far from a complete explanation of the complex subject of inheritance. + The idea here is for you to be able to understand how to use inheritance in + creating your objects. A full discussion will follow in a later textbook. + Right now you should know the following: + 1) Each mudlib has a library of generic objects with their own general + functions used by creators through inheritance to make coding objects + easier and to make interaction between objects smoother. + 2) The functions in the inheritable files of a mudlib vary from mudlib + to mudlib. There should exist documentation on your mud on how to + use each inheritable file. If you are unaware what functions are + available, then there is simply no way for you to use them. Always + pay special attention to the data types of the input and the data + types of ay output. + 3) You inherit the functionality of another object through the line: + + ----- + inherit "filename"; + ----- + + where filename is the name of the file of the object to be inherited. + This line goes at the beginning of your code. + + Note: + You may see the syntax ::create() or ::init() or ::reset() in places. + You do not need fully to understand at this point the full nuances of this, + but you should have a clue as to what it is. The "::" operator is a way + to call a function specifically in an inherited object (called the scope + resolution operator). For instance, most muds' room.c has a function + called create(). When you inherit room.c and configure it, you are doing + what is called overriding the create() function in room.c. This means + that whenever ANYTHING calls create(), it will call *your* version and not + the one in room.c. However, there may be important stuff in the room.c + version of create(). The :: operator allows you to call the create() in + room.c instead of your create(). + An example: + + ----- + #1 + + inherit "/std/room"; + + void create() { create(); } + ----- + + ----- + #2 + + inherit "/std/room"; + + void create() { ::create(); } + ----- + + Example 1 is a horror. When loaded, the driver calls create(), and then + create() calls create(), which calls create(), which calls create()... + In other words, all create() does is keep calling itself until the driver + detects a too deep recursion and exits. + + Example 2 is basically just a waste of RAM, as it is no different from room.c + functionally. With it, the driver calls its create(), which in turn calls + ::create(), the create() in room.c. Otherwise it is functionally + exactly the same as room.c. diff -c -r --new-file ds1.1/lib/doc/manual/chapter06 ds2.1/lib/doc/manual/chapter06 *** ds1.1/lib/doc/manual/chapter06 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter06 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,334 ---- + chapter 6 "Variable Handling" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: july 5 1993 + + CHAPTER 6: Variable Handling + + 6.1 Review + By now you should be able to code some simple objects using your muds standard + object library. Inheritance allows you to use functions defined in those + objects without having to go and define yourself. In addition, + you should know how to declare your own functions. This + chapter will teach you about the basic elements of LPC which will allow you to + define your own functions using the manipulation of variables. + + 6.2 Values and objects + Basically, what makes objects on the mud different are two things: + 1) Some have different functions + 2) All have different values + + Now, all player objects have the same functions. They are therefore + differentiated by the values they hold. For instance, the player + named "Forlock" is different from "Descartes" *at least* in that they + have different values for the variable true_name, those being + "descartes" and "forlock". + + Therefore, changes in the game involve changes in the values of the objects + in the game. Functions are used to name specific process for manipulating + values. For instance, the create() function is the function whose + process is specifically to initialize the values of an object. + Within a function, it is specifically things called instructions which are + responsible for the direct manipulation of variables. + + 6.3 Local and global variables + Like variables in most programming language, LPC variables may be declared + as variables "local" to a specific function, or "globally" available + to all functions. Local variables are declared inside the function which + will use them. No other function knows about their existence, since + the values are only stored in memory while that function is being executed. + A global variable is available to any function which comes after its + declaration in the object code. Since global variables take up RAM for + the entire existence of the object, you should use them only when + you need a value stored for the entire existence of the object. + Have a look at the following 2 bits of code: + + ----- + int x; + + int query_x() { return x; } + + void set_x(int y) { x = y; } + ----- + + ----- + void set_x(int y) { + int x; + + x = y; + write("x is set to x"+x+" and will now be forgotten.\n"); + } + ----- + + In the first example, x is declared outside of any functions, and therefore + will be available to any function declared after it. In that example, + x is a global variable. + In the second example, x is declared inside the function set_x(). It + only exists while the function set_x() is being executed. Afterwards, + it ceases to exist. In that example, x is a local variable. + + 6.4 Manipulating the values of variables + Instructions to the driver are used to manipulate the values of variables. + An example of an instruction would be: + + ----- + x = 5; + ----- + + The above instruction is self-explanatory. It assigns to the variable + x the value 5. However, there are some important concepts in involved + in that instruction which are involved in instructions in general. + The first involves the concept of an expression. An expression is + any series of symbols which have a value. In the above instruction, + the variable x is assigned the value of the expression 5. Constant + values are the simplest forms in which expressions can be put. A constant + is a value that never changes like the int 5 or the string "hello". + The last concept is the concept of an operator. In the above example, + the assignment operator = is used. + + There are however many more operators in LPC, and expressions can get + quite complex. If we go up one level of complexity, we get: + + ----- + y = 5; + x = y +2; + ----- + + The first instruction uses the assignment operator to assign the value + of the constant expression 5 to the variable y. The second one + uses the assignment operator to assign to x the value of the expression + (y+2) which uses the addition operator to come up with a value which + is the sum of the value of y and the value of the constant expression 2. + Sound like a lot of hot air? + + In another manner of speaking, operators can be used to form complex + expressions. In the above example, there are two expressions in the + one instruction x = y + 2;: + 1) the expression y+2 + 2) the expression x = y + 2 + As stated before, all expressions have a value. The expression + y+2 has the value of the sum of y and 2 (here, 7); + The expression x = y + 2 *also* has the value of 7. + So operators have to important tasks: + 1) They *may* act upon input like a function + 2) They evaluate as having a value themselves. + Now, not all operators do what 1 does. The = operators does act upon + the value of 7 on its right by assigning that value to x. The operator + + however does nothing. They both, however, have their own values. + + 6.5 Complex expressions + As you may have noticed above, the expression x = 5 *itself* has a value + of 5. In fact, since LPC operators themselves have value as expressions, + they cal allow you to write some really convoluted looking nonsense like: + i = ( (x=sizeof(tmp=users())) ? --x : sizeof(tmp=children("/std/monster"))-1) + which says basically: + assing to tmp the array returned by the efun users(), then assign to x + the value equal to the number of elements to that array. If the value + of the expression assigning the value to x is true (not 0), then assign + x by 1 and assign the value of x-1 to i. If x is false though, + then set tmp to the array returned by the efun children(), and then + assign to i the value of the number of members in the array tmp -1. + Would you ever use the above statement? I doubt it. However you might + see or use expressions similar to it, since the ability to consolidate + so much information into one single line helps to speed up the execution of + your code. A more often used version of this property of LPC operators + would be something like: + x = sizeof(tmp = users()); + while(i--) write((string)tmp[i]->GetKeyName()+"\n"); + instead of writing something like: + tmp = users(); + x = sizeof(tmp); + for(i=0; i<x; i++) write((string)tmp[i]->GetKeyName()+"\n"); + Things like for(), while(), arrays and such will be explained later. + But the first bit of code is more concise and it executed faster. + + NOTE: A detailed description of all basic LPC operators follows the chapter + summary. + + + 6.6 Chapter Summary + You now know how to declare variables and understand the difference between + declaring and using them globally or locally. Once you become familiar + with your driver's efuns, you can display those values in many different + ways. In addition, through the LPC operators, you know how to change + and evaluate the values contained in variables. This is useful of course + in that it allows you to do something like count how many apples have + been picked from a tree, so that once all apples have been picked, no + players can pick more. Unfortunately, you do not know how to have + code executed in anything other than a linera fashion. In other words, + hold off on that apple until the next chapter, cause you do not know + how to check if the apples picked is equal to the number of apples in the + tree. You also do not know about the special function init() where you + give new commands to players. But you are almost ready to code a nice, + fairly complex area. + + 6.7 LPC operators + This section contains a detailed listing of the simpler LPC operators, + including what they do to the values they use (if anything) and the value + that they have. + + The operators described here are: + = + - * / % += -= *= /= %= + -- ++ == != > < >= <= ! && || + -> ? : + + Those operators are all described in a rather dry manner below, but it is best + to at least look at each one, since some may not behave *exactly* as + you think. But it should make a rather good reference guide. + + = assignment operator: + example: x = 5; + value: the value of the variable on the *left* after its function is done + explanation: It takes the value of any expression on the *right* and + assigns it to the variable on the *left*. Note that you must use + a single variable on the left, as you cannot assign values to + constants or complex expressions. + + + addition operator: + example: x + 7 + value: The sum of the value on the left and the value on the right + exaplanation: It takes the value of the expression on the right and + adds it to the value of the expression on the left. For values + of type int, this means the numerical sum. For strings, + it means that the value on the right is stuck onto the value on + the left ("ab" is the value of "a"+"b"). This operator does not + modify any of the original values (i.e. the variable x from + above retains its old value). + + - subtraction operator: + example: x - 7 + value: the value of the expression on the left reduced by the right + explanation: Same characteristics as addition, except it subtracts. + With strings: "a" is the value of "ab" - "b" + + * multiplication operator: + example: x*7 + value and explanation: same as with adding and subtracting except + this one performs the math of multiplication + + / division operator: + example: x/7 + value and explanation: see above + + += additive assignment operator: + example: x += 5 + value: the same as x + 5 + exaplanation: It takes the value of the variable on the left + and the value of the expression on the right, adds them together + and assigns the sum to the variable on the left. + example: if x = 2... x += 5 assigns the value + 7 to the variable x. The whole expression + has the value of 7. + + -= subtraction assignment operator + example: x-=7 + value: the value of the left value reduced by the right value + examplanation: The same as += except for subtraction. + + *= multiplicative assignment operator + example: x *= 7 + value: the value of the left value multiplied by the right + explanation: Similar to -= and += except for addition. + + /= division assignment operator + example: x /= 7 + value: the value of the variable on the left divided by the right value + explanation: similar to above, except with division + + ++ post/pre-increment operators + examples: i++ or ++i + values: + i++ has the value of i + ++i has the value of i+1 + explanation: ++ changes the value of i by increasing it by 1. + However, the value of the expression depends on where you + place the ++. ++i is the pre-increment operator. This means + that it performs the increment *before* giving a value. + i++ is the post-ncrement operator. It evalutes before incrementing + i. What is the point? Well, it does not much matter to you at + this point, but you should recognize what it means. + + -- post/pre-decrement operators + examples: i-- or --i + values: + i-- the value of i + --i the value of i reduced by 1 + explanation: like ++ except for subtraction + + == equality operator + example: x == 5 + value: true or false (not 0 or 0) + explanation: it does nothing to either value, but + it returns true if the 2 values are the same. + It returns false if they are not equal. + + != inequality operator + example: x != 5 + value: true or false + explanation returns true if the left expression is not equal to the right + expression. It returns fals if they are equal + + > greater than operator + example: x > 5 + value: true or false + explanation: true only if x has a value greater than 5 + false if the value is equal or less + + < less than operator + >= greater than or equal to operator + <= less than or equal to operator + examples: x < y x >= y x <= y + values: true or false + explanation: similar as to > except + < true if left is less than right + >= true if left is greater than *or equal to* right + <= true if the left is less than *or equal to* the right + + && logical and operator + || logical or operator + examples: x && y x || y + values: true or false + explanation: If the right value and left value are non-zero, && is true. + If either are false, then && is false. + For ||, only one of the values must be true for it to evaluate + as true. It is only false if both values indeed + are false + + ! negation operator + example: !x + value: true or false + explanation: If x is true, then !x is false + If x is false, !x is true. + + A pair of more complicated ones that are here just for the sake of being + here. Do not worry if they utterly confuse you. + + -> the call other operator + example: this_player()->GetKeyName() + value: The value returned by the function being called + explanation: It calls the function which is on the right in the object + on the left side of the operator. The left expression *must* be + an object, and the right expression *must* be the name of a function. + If not such function exists in the object, it will return 0 (or + more correctly, undefined). + + ? : conditional operator + example: x ? y : z + values: in the above example, if x is try, the value is y + if x is false, the value of the expression is z + explanation: If the leftmost value is true, it will give the expression as + a whole the value of the middle expression. Else, it will give the + expression as a whole the value of the rightmost expression. + + A note on equality: A very nasty error people make that is VERY difficult + to debug is the error of placing = where you mean ==. Since + operators return values, they both make sense when being evaluated. + In other words, no error occurs. But they have very different values. For example: + if(x == 5) if(x = 5) + The value of x == 5 is true if the value of x is 5, false othewise. + The value of x = 5 is 5 (and therefore always true). + The if statement is looking for the expression in () to be either true or false, + so if you had = and meant ==, you would end up with an expression that is + always true. And you would pull your hair out trying to figure out + why things were not happening like they should :) diff -c -r --new-file ds1.1/lib/doc/manual/chapter07 ds2.1/lib/doc/manual/chapter07 *** ds1.1/lib/doc/manual/chapter07 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter07 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,433 ---- + chapter 7 "Flow Control" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 10 july 1993 + + CHAPTER 7: Flow Control + + 7.1 Review of variables + Variables may be manipulated by assigning or changing values with the + expressions =, +=, -=, ++, --. Those expressions may be combined with + the expressions -, +, *, /, %. However, so far, you have only been + shown how to use a function to do these in a linear way. For example: + + int hello(int x) { + x--; + write("Hello, x is "+x+".\n"); + return x; + } + + is a function you should know how to write and understand. But what + if you wanted to write the value of x only if x = 1? Or what if + you wanted it to keep writing x over and over until x = 1 before + returning? LPC uses flow control in exactly the same way as C and C++. + + 7.2 The LPC flow control statements + LPC uses the following expressions: + + if(expression) instruction; + + if(expression) instruction; + else instruction; + + if(expression) instruction; + else if(expression) instruction; + else instruction; + + while(expression) instruction; + + do { instruction; } while(expression); + + switch(expression) { + case (expression): instruction; break; + default: instruction; + } + + Before we discuss these, first something on what is meant by expression and + instruction. An expression is anything with a value like a variable, + a comparison (like x>5, where if x is 6 or more, the value is 1, else the + value is 0), or an assignment(like x += 2). An instruction can be any + single line of lpc code like a function call, a value assignment or + modification, etc. + + You should know also the operators &&, ||, ==, !=, and !. These are the + logical operators. They return a nonzero value when true, and 0 when false. + Make note of the values of the following expressions: + + (1 && 1) value: 1 (1 and 1) + (1 && 0) value: 0 (1 and 0) + (1 || 0) value: 1 (1 or 0) + (1 == 1) value: 1 (1 is equal to 1) + (1 != 1) value: 0 (1 is not equal to 1) + (!1) value: 0 (not 1) + (!0) value: 1 (not 0) + + In expressions using &&, if the value of the first item being compared + is 0, the second is never tested even. When using ||, if the first is + true (1), then the second is not tested. + + 7.3 if() + The first expression to look at that alters flow control is if(). Take + a look at the following example: + + 1 void reset() { + 2 int x; + 3 + 4 ::reset(); + 5 x = random(10); + 6 if(x > 50) SetSearch_func("floorboards", "search_floor"); + 7 } + + The line numbers are for reference only. + In line 2, of course we declare a variable of type int called x. Line 3 + is aethetic whitespace to clearly show where the declarations end and the + function code begins. The variable x is only available to the function + reset(). + Line 4 makes a call to the room.c version of reset(). + Line 5 uses the driver efun random() to return a random number between + 0 and the parameter minus 1. So here we are looking for a number between + 0 and 99. + In line 6, we test the value of the expression (x>50) to see if it is true + or false. If it is true, then it makes a call to the room.c function + SetSearch_func(). If it is false, the call to SetSearch_func() is never + executed. + In line 7, the function returns driver control to the calling function + (the driver itself in this case) without returning any value. + + If you had wanted to execute multiple instructions instead of just the one, + you would have done it in the following manner: + + if(x>50) { + SetSearch_func("floorboards", "search_floor"); + if(!present("beggar", this_object())) make_beggar(); + } + + Notice the {} encapsulate the instructions to be executed if the test + expression is true. In the example, again we call the room.c function + which sets a function (search_floor()) that you will later define yourself + to be called when the player types "search floorboards" (NOTE: This is + highly mudlib dependent. Nightmare mudlibs have this function call. + Others may have something similar, while others may not have this feature + under any name). Next, there is another if() expression that tests the + truth of the expression (!present("beggar",this_object())). The ! in the + test expression changes the truth of the expression which follows it. In + this case, it changes the truth of the efun present(), which will return + the object that is a beggar if it is in the room (this_object()), or it + will return 0 if there is no beggar in the room. So if there is a beggar + still living in the room, (present("beggar", this_object())) will have + a value equal to the beggar object (data type object), otherwise it will + be 0. The ! will change a 0 to a 1, or any nonzero value (like the + beggar object) to a 0. Therefore, the expression + (!present("beggar", this_object())) is true if there is no beggar in the + room, and false if there is. So, if there is no beggar in the room, + then it calls the function you define in your room code that makes a + new beggar and puts it in the room. (If there is a beggar in the room, + we do not want to add yet another one :)) + + Of course, if()'s often comes with ands or buts :). In LPC, the formal + reading of the if() statement is: + + if(expression) { set of intructions } + else if(expression) { set of instructions } + else { set of instructions } + + This means: + + If expression is true, then do these instructions. + Otherise, if this second expression is true, do this second set. + And if none of those were true, then do this last set. + + You can have if() alone: + + if(x>5) write("Foo,\n"); + + with an else if(): + + if(x > 5) write("X is greater than 5.\n"); + else if(x >2) write("X is less than 6, but greater than 2.\n"); + + with an else: + + if(x>5) write("X is greater than 5.\n"); + else write("X is less than 6.\n"); + + or the whole lot of them as listed above. You can have any number of + else if()'s in the expression, but you must have one and only one + if() and at most one else. Of course, as with the beggar example, + you may nest if() statements inside if() instructions. (For example, + if(x>5) { + if(x==7) write("Lucky number!\n"); + else write("Roll again.\n"); + } + else write("You lose.\n"); + + 7.4 The statements: while() and do {} while() + Prototype: + while(expression) { set of instructions } + do { set of instructions } while(expression); + + These allow you to create a set of instructions which continue to + execute so long as some expression is true. Suppose you wanted to + set a variable equal to a player's level and keep subtracting random + amounts of either money or hp from a player until that variable equals + 0 (so that player's of higher levels would lose more). You might do it + this way: + + 1 int x; + 2 + 3 x = (int)this_player()->query_level(); /* this has yet to be explained */ + 4 while(x > 0) { + 5 if(random(2)) this_player()->add_money("silver", -random(50)); + 6 else this_player()->add_hp(-(random(10)); + 7 x--; + 8 } + + The expression this_player()->query_level() calIn line 4, we start a loop that executes so long as x is greater than 0. + Another way we could have done this line would be: + while(x) { + The problem with that would be if we later made a change to the funtion + y anywhere between 0 and 49 coins. + In line 6, if instead it returns 0, we call the add_hp() function in the + player which reduces the player's hit points anywhere between 0 and 9 hp. + In line 7, we reduce x by 1. + At line 8, the execution comes to the end of the while() instructions and + goes back up to line 4 to see if x is still greater than 0. This + loop will keep executing until x is finally less than 1. + + You might, however, want to test an expression *after* you execute some + instructions. For instance, in the above, if you wanted to execute + the instructions at least once for everyone, even if their level is + below the test level: + + int x; + + x = (int)this_player()->query_level(); + do { + if(random(2)) this_player()->add_money("silver", -random(50)); + else this_player()->add_hp(-random(10)); + x--; + } while(x > 0); + + This is a rather bizarre example, being as few muds have level 0 players. + And even still, you could have done it using the original loop with + a different test. Nevertheless, it is intended to show how a do{} while() + works. As you see, instead of initiating the test at the beginning of the + loop (which would immediately exclude some values of x), it tests after + the loop has been executed. This assures that the instructions of the loop + get executed at least one time, no matter what x is. + + 7.5 for() loops + Prototype: + for(initialize values ; test expression ; instruction) { instructions } + + initialize values: + This allows you to set starting values of variables which will be used + in the loop. This part is optional. + + test expression: + Same as the expression in if() and while(). The loop is executed + as long as this expression (or expressions) is true. You must have a + test expression. + + instruction: + An expression (or expressions) which is to be executed at the end of each + loop. This is optional. + + Note: + for(;expression;) {} + IS EXACTLY THE SAME AS + while(expression) {} + + Example: + + 1 int x; + 2 + 3 for(x= (int)this_player()->query_level(); x>0; x--) { + 4 if(random(2)) this_player()->add_money("silver", -random(50)); + 5 else this_player()->add_hp(-random(10)); + 6 } + + This for() loop behaves EXACTLY like the while() example. + Additionally, if you wanted to initialize 2 variables: + + for(x=0, y=random(20); x<y; x++) { write(x+"\n"); } + + Here, we initialize 2 variables, x and y, and we separate them by a + comma. You can do the same with any of the 3 parts of the for() + expression. + + 7.6 The statement: switch() + Prototype: + switch(expression) { + case constant: instructions + case constant: instructions + ... + case constant: instructions + default: instructions + } + + This is functionally much like if() expressions, and much nicer to the + CPU, however most rarely used because it looks so damn complicated. + But it is not. + + First off, the expression is not a test. The cases are tests. A English + sounding way to read: + + 1 int x; + 2 + 3 x = random(5); + 4 switch(x) { + 5 case 1: write("X is 1.\n"); + 6 case 2: x++; + 7 default: x--; + 8 } + 9 write(x+"\n"); + + is: + + set variable x to a random number between 0 and 4. + In case 1 of variable x write its value add 1 to it and subtract 1. + In case 2 of variable x, add 1 to its value and then subtract 1. + In other cases subtract 1. + Write the value of x. + + switch(x) basically tells the driver that the variable x is the value + we are trying to match to a case. + Once the driver finds a case which matches, that case *and all following + cases* will be acted upon. You may break out of the switch statement + as well as any other flow control statement with a break instruction in + order only to execute a single case. But that will be explained later. + The default statement is one that will be executed for any value of + x so long as the switch() flow has not been broken. You may use any + data type in a switch statement: + + string name; + + name = (string)this_player()->GetKeyName(); + switch(name) { + case "descartes": write("You borg.\n"); + case "flamme": + case "forlock": + case "shadowwolf": write("You are a Nightmare head arch.\n"); + default: write("You exist.\n"); + } + + For me, I would see: + You borg. + You are a Nightmare head arch. + You exist. + + Flamme, Forlock, or Shadowwolf would see: + You are a Nightmare head arch. + You exist. + + Everyone else would see: + You exist. + + 7.7 Altering the flow of functions and flow control statements + The following instructions: + return continue break + + alter the natural flow of things as described above. + First of all, + return + no matter where it occurs in a function, will cease the execution of that + function and return control to the function which called the one the + return statement is in. If the function is NOT of type void, then a + value must follow the return statement, and that value must be of a + type matching the function. An absolute value function would look + like this: + + int absolute_value(int x) { + if(x>-1) return x; + else return -x; + } + + In the second line, the function ceases execution and returns to the calling + function because the desired value has been found if x is a positive + number. + + continue is most often used in for() and while statements. It serves + to stop the execution of the current loop and send the execution back + to the beginning of the loop. For instance, say you wanted to avoid + division by 0: + + x= 4; + while( x > -5) { + x-- + if(!x) continue; + write((100/x)+"\n"); + } + write("Done.\n") + + You would see the following output: + 33 + 50 + 100 + -100 + -50 + -33 + -25 + Done. + To avoid an error, it checks in each loop to make sure x is not 0. + If x is zero, then it starts back with the test expression without + finishing its current loop. + + In a for() expression + for(x=3; x>-5; x--) { + if(!x) continue; + write((100/x)+"\n"); + } + write("Done.\n"); + It works much the same way. Note this gives exactly the same output + as before. At x=1, it tests to see if x is zero, it is not, so it + writes 100/x, then goes back to the top, subtracts one from x, checks to + see if it is zero again, and it is zero, so it goes back to the top + and subtracts 1 again. + + break + This one ceases the function of a flow control statement. No matter + where you are in the statement, the control of the program will go + to the end of the loop. So, if in the above examples, we had + used break instead of continue, the output would have looked like this: + + 33 + 50 + 100 + Done. + + continue is most often used with the for() and while() statements. + break however is mostly used with switch() + + switch(name) { + case "descartes": write("You are borg.\n"); break; + case "flamme": write("You are flamme.\n"); break; + case "forlock": write("You are forlock.\n"); break; + case "shadowwolf": write("You are shadowwolf.\n"); break; + default: write("You will be assimilated.\n"); + } + + This functions just like: + + if(name == "descartes") write("You are borg.\n"); + else if(name == "flamme") write("You are flamme.\n"); + else if(name == "forlock") write("You are forlock.\n"); + else if(name == "shadowwolf") write("You are shadowwolf.\n"); + else write("You will be assimilated.\n"); + + except the switch statement is much better on the CPU. + If any of these are placed in nested statements, then they alter the + flow of the most immediate statement. + + 7.8 Chapter summary + This chapter covered one hell of a lot, but it was stuff that needed to + be seen all at once. You should now completely understand if() for() + while() do{} while() and switch(), as well as how to alter their flow + using return, continue, and break. Effeciency says if it can be done in + a natural way using switch() instead of a lot of if() else if()'s, then + by all means do it. You were also introduced to the idea of calling + functions in other objects. That however, is a topic to be detailed later. + You now should be completely at ease writing simple rooms (if you have + read your mudlib's room building document), simple monsters, and + other sorts of simple objects. diff -c -r --new-file ds1.1/lib/doc/manual/chapter08 ds2.1/lib/doc/manual/chapter08 *** ds1.1/lib/doc/manual/chapter08 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter08 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,196 ---- + chapter 8 "LPC Basics" + LPC Basics + Written by Descartes of Borg + first edition: 23 april 1993 + second edition: 12 july 1993 + + CHAPTER 8: The data type "object" + + 8.1 Review + You should now be able to do anything so long as you stick to calling + functions within your own object. You should also know, that at the + bare minimum you can get the create() (or reset()) function in your object + called to start just by loading it into memory, and that your reset() + function will be called every now and then so that you may write the + code necessary to refresh your room. Note that neither of these + functions MUST be in your object. The driver checks to see if the + function exists in your object first. If it does not, then it does not + bother. You are also acquainted with the data types void, int, and string. + + 7.2 Objects as data types + In this chapter you will be acquainted with a more complex data type, + object. An object variable points to a real object loaded into the + driver's memory. You declare it in the same manner as other data types: + object ob; + It differs in that you cannot use +, -, +=, -=, *, or / (what would it + mean to divide a monster by another monster?). And since efuns like + say() and write() only want strings or ints, you cannot write() or + say() them (again, what would it mean to say a monster?). + But you can use them with some other of the most important efuns on any + LPMud. + + 8.3 The efun: this_object() + This is an efun which returns an object in which the function being executed + exists. In other words, in a file, this_object() refers to the object your + file is in whether the file gets cloned itself or inherted by another file. + It is often useful when you are writing a file which is getting inherited + by another file. Say you are writing your own living.c which gets + inherited by user.c and monster.c, but never used alone. You want to log + the function set_level() it is a player's level being set (but you do not + care if it is a monster. + You might do this: + + void set_level(int x) { + if(this_object()->is_player()) log_file("levels", "foo\n"); + level = x; + } + + Since is_player() is not defined in living.c or anything it inherits, + just saying if(is_player()) will result in an error since the driver + does not find that function in your file or anything it inherits. + this_object() allows you to access functions which may or may not be + present in any final products because your file is inherited by others + without resulting in an error. + + 8.4 Calling functions in other objects + This of course introduces us to the most important characteristic of + the object data type. It allows us to access functions in other objects. + In previous examples you have been able to find out about a player's level, + reduce the money they have, and how much hp they have. + Calls to functions in other objects may be done in two ways: + + object->function(parameters) + call_other(object, "function", parameters); + + example: + this_player()->add_money("silver", -5); + call_other(this_player(), "add_money", "silver", -5); + + In some (very loose sense), the game is just a chain reaction of function + calls initiated by player commands. When a player initiates a chain of + function calls, that player is the object which is returned by + the efun this_player(). So, since this_player() can change depending + on who initiated the sequence of events, you want to be very careful + as to where you place calls to functions in this_player(). The most common + place you do this is through the last important lfun (we have mentioned + create() and reset()) init(). + + 8.5 The lfun: init() + Any time a living thing encounters an object (enters a new room, or enters + the same room as a certain other object), init() is called in all of + the objects the living being newly encounters. It is at this point + that you can add commands the player can issue in order to act. + Here is a sample init() function in a flower. + + void init() { + ::init(); + add_action("smell_flower", "smell"); + } + + Ito smell_flower(). So you should have smell_flower() look like this: + + 1 int smell_flower(string str); /* action functions are type int */ + 2 + 3 int smell_flower(string str) { + 4 if(str != "flower") return 0; /* it is not the flower being smelled */ + 5 write("You sniff the flower.\n"); + 6 say((string)this_player()->GetName()+" smells the flower.\n"); + 7 this_player()->add_hp(random(5)); + 8 return 1; + 9 } + + In line 1, we have our function declared. + In line 3, smell_flower() begins. str becomes whatever comes after the + players command (not including the first white space). + In line 4, it checks to see if the player had typed "smell flower". If + the player had typed "smell cheese", then str would be "cheese". If + it is not in fact "flower" which is being smelled, then 0 is returned, + letting the driver know that this was not the function which should + have been called. If in fact the player had a piece of cheese as well + which had a smell command to it, the driver would then call the function + for smelling in that object. The driver will keep calling all functions + tied to smell commands until one of them returns 1. If they all return + 0, then the player sees "What?" + In line 5, the efun write() is called. write() prints the string which + is passed to it to this_player(). So whoever typed the command here + sees "You sniff the flower." + In line 6, the efun say() is called. say() prints the string which is + doing the sniffing, we have to call the GetName() function + in this_player(). That way if the player is invis, it will say + "Someone" (or something like that), and it will also be properly + capitalized. + In line 7, we call the add_hp() function in the this_player() object, + since we want to do a little healing for the sniff (Note: do not + code this object on your mud, whoever balances your mud will shoot you). + In line 8, we return control of the game to the driver, returning 1 to + let it know that this was in fact the right function to call. + + 8.6 Adding objects to your rooms + And now, using the data type object, you can add monsters to your rooms: + + void create() { + ::create(); + SetProperty("light", 3); + set("short", "Krasna Square"); + set("long", "Welcome to the Central Square of the town of Praxis.\n"); + SetExits( ({ "/domains/standard/hall" }), ({ "east" }) ); + } + + void reset() { + object ob; + + ::reset(); + if(present("guard")) return; /* Do not want to add a guard if */ + ob = new("/std/monster"); /* one is already here */ + ob->SetKeyName("guard"); + ob->set("id", ({ "guard", "town guard" }) ); + ob->set("short", "Town guard"); + ob->set("long", "He guards Praxis from nothingness.\n"); + ob->SetGender("male"); + ob->set_race("human"); + ob->set_level(10); + ob->set_alignment(200); + ob->set_humanoid(); + ob->set_hp(150); + ob->set_wielding_limbs( ({ "right hand", "left hand" }) ); + ob->eventMove(this_object()); + } + + Now, this will be wildly different on most muds. Some, as noted before, + in that object so you have a uniquely configured monster object. The + last act in native muds is to call eventMove() in the monster object to move + it to this room (this_object()). In compat muds, you call the efun + move_object() which takes two parameters, the object to be moved, and the + object into which it is being moved. + + 8.7 Chapter summary + At this point, you now have enough knowledge to code some really nice + stuff. Of course, as I have been stressing all along, you really need + to read the documents on building for your mud, as they detail which + functions exist in which types of objects for you to call. No matter + what your knowledge of the mudlib is, you have enough know-how to + give a player extra things to do like sniffing flowers or glue or whatever. + At this point you should get busy coding stuff. But the moment things + even look to become tedious, that means it is time for you to move to + the next level and do more. Right now code yourself a small area. + Make extensive use of the special functions coded in your mud's + room.c (search the docs for obscure ones no one else seems to use). + Add lots o' neat actions. Create weapons which have magic powers which + gradually fade away. All of this you should be able to do now. Once + this becomes routine for you, it will be time to move on to intermediate + stuff. Note that few people actually get to the intermediate stuff. + If you have played at all, you notice there are few areas on the mud + which do what I just told you you should be able to do. It is not + because it is hard, but because there is a lot of arrogance out there + on the part of people who have gotten beyond this point, and very little + communicating of that knowledge. The trick is to push yourself and + think of something you want to do that is impossible. If you ask someone + in the know how to do X, and they say that is impossible, find out + youself how to code it by experimenting. + + George Reese + Descartes of Borg + 12 july 1993 + borg@hebron.connected.com + Descartes@Nightmare (intermud) + Descartes@Igor (not intermud) diff -c -r --new-file ds1.1/lib/doc/manual/chapter09 ds2.1/lib/doc/manual/chapter09 *** ds1.1/lib/doc/manual/chapter09 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter09 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,144 ---- + chapter 9 "Introduction to Intermediate LPC" + Intermediate LPC + Descartes of Borg + Novermber 1993 + + Chapter 1: Introduction + + 1.1 LPC Basics + Anyone reading this textbook should either have read the textbook LPC + Basics or be familiar enough with mud realm coding such that not only are + they capable of building rooms and other such objects involved in area + coding, but they also have a good idea of what is going on when the code + they write is executing. If you do not feel you are at this point, then go + back and read LPC Basics before continuing. If you do so, you will find + that what you read here will be much more meaningful to you. + + 1.2 Goals of This Textbook + The introductory textbook was meant to take people new to LPC from + knowing nothing to being able to code a nice realm on any LPMud. There + is naturally much more to LPC and to LPMud building, however, than + building rooms, armours, monsters, and weapons. As you get into more + complicated concepts like guilds, or desire to do more involved things with + your realm, you will find the concepts detailed in LPC Basics to be lacking + in support for these projects. Intermediate LPC is designed to take you + beyond the simple realm building process into a full knowledge of LPC for + functioning as a realm builder on an LPMud. The task of mudlib building + itself is left to a later text. After reading this textbook and working through + it by experimenting with actual code, the reader should be able to code game + objects to fit any design or idea they have in mind, so long as I have been + successful. + + 1.3 An Overview + What more is there? Well many of you are quite aware that LPC supports + mappings and arrays and have been asking me why those were not detailed + in LPC Basics. I felt that those concepts were beyond the scope of what I + was trying to do with that textbook and were more fitting to this textbook. + But new tools are all fine and dandy, what matters, however, is what you + can do with those tools. The goal of LPC Basics was to get you to building + quality LPMud realms. Mappings and arrays are not necessary to do that. + The goal of this book is to allow you to code any idea you might want to + code in your area. That ability requires the knowledge of mappings and + arrays. + + Any idea you want to code in an LPMud is possible. LPC is a language + which is amazingly well suited to this task. All that prevents you from + coding your ideas is your knowledge of LPC or an inadequate mudlib or + your mudÕs theme or administrative policies. This textbook cannot make + the mudlib you are working with any better, and it cannot change the mud + theme or the mudÕs administrative policies. Never once think that LPC is + incapable of doing what you want to do. If your idea is prevented by + administrative policies or themes, then it is simply not an idea for your + current mud. If the mudlib is inadequate, talk to the people in charge of + your mudlib about what can be done at the mudlib level to facilitate it. You + would be surprised by what is actually in the mudlib you did not know + about. More important, after reading this textbook, you should be able to + read all of the mudlib code in your mudÕs mudlib and understand what is + going on at each line in the mudlib code. You may not as yet be able to + reproduce that code on your own, but at least you can understand what is + going on at the mudlib level. + + This textbook starts out with a discussion about what the LPMud driver is + doing. One nice thing about this textbook, in general it is completely driver + and mudlib independent (excepting for the Dworkin Game Driver). The + chapter on the game driver does not get into actual implementation, but + instead deals with what all game drivers basically do in order to run the + mud. + + Next I discuss those magic topics everyone wants to know more about, + arrays and mappings. Mappings may be simultaneously the easiest and + most difficult data type to understand. Since they are sort of complex arrays + in a loose sense, you really need to understand arrays before discussing + them. All the same, once you understand them, they are much easier than + arrays to use in real situations. At any rate, spend most of your time + working with that chapter, because it is probably the most difficult, yet most + useful chapter in the book. + + After that follows a brief chapter on the LPC pre-compiler, a tool you can + use for sorting out how your code will look before it gets sent to the + compiler. Despite my horrid intro to it here, this chapter is perhaps the + easiest chapter in the textbook. I put it after the mappings and arrays + chapter for exactly that reason. + + Strings are re-introduced next, going into more detail with how you can do + such things as advanced command handling by breaking up strings. Once + you understand arrays fairly well, this chapter should be really simple. + + The next chapter is the second most important in the book. It may be the + most important if you ever intend to go beyond the intermediate stage and + dive into mudlib coding. That chapter involves the complex ideas behind + LPC inheritance. Since the goal of this textbook is not to teach mudlib + programming, the chapter is not a detailed discussion on object oriented + programming. Understanding this chapter, however, will give you some + good insights into what is involved with object oriented programming, as + well as allow you to build more complex objects by overriding functions + and defining your own base classes. + + Finally, the textbook ends with a simple discussion of code debugging. + This is not an essential chapter, but instead it is meant as more of an + auxiliary supplement to what the knowledge you have accumulated so far. + + 1.4 Not Appearing in This Textbook + Perhaps what might appear to some as the most glaring omission of this + textbook is largely a political omission, shadows. Never have I ever + encountered an example of where a shadow was either the best or most + effecient manner of doing anything. It does not follow from that, however, + that there are no uses for shadows. My reasoning for omitting shadows + from this textbook is that the learner is best served by learning the concepts + in this textbook first and having spent time with them before dealing with + the subject of shadows. In that way, I feel the person learning LPC will be + better capable of judging the merits of using a shadow down the road. I + will discuss shadows in a future textbook. + + If you are someone who uses shadows some or a lot, please do not take the + above paragraph as a personal attack. There may be some perfectly valid + uses for shadows somewhere which I have yet to encounter. Nevertheless, + they are not the ideal way to accomplish any given task, and therefore they + are not considered for the purposes of this textbook an intermediate coding + tool. + + I have also omitted discussions of security and object oriented + programming. Both are quite obviously mudlib issues. Many people, + however, might take exception with my leaving out a discussion of object + oriented programming. I chose to leave that for a later text, since most area + builders code for the creativity, not for the computer science theory. In both + the intermediate and beginner textbooks, I have chosen only to discuss + theory where it is directly applicable to practical LPC programming. For + people who are starting out green in LPC and want to code the next great + mudlib, perhaps theory would be more useful. But for the purposes of this + book, a discussion of object oriented programming is simply a snoozer. I + do plan to get heavy into theory with the next textbook. + + 1.5 Summary + LPC is not difficult to learn. It is a language which, although pathetic + compared to any other language for performing most computer language + tasks, is incredibly powerful and unequalled for the tasks of building an + area in MUD type games. For the beginner, it allows you to easily jump in + and code useful objects without even knowing what you are doing. For the + intermediate person, it allows you to turn any idea you have into textual + virtual reality. And for the advanced person, itÕs object oriented features + can allow you to build one of the most popular games on the internet. What + you can do is simply limited by how much you know. And learning more + does not require a computer science degree. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/manual/chapter10 ds2.1/lib/doc/manual/chapter10 *** ds1.1/lib/doc/manual/chapter10 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter10 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,224 ---- + chapter 10 "The LPMud Driver" + Intermediate LPC + Descartes of Borg + Novermber 1993 + + Chapter 2: The LPMud Driver + + 2.1 Review of Basic Driver/Mudlib Interaction + In the LPC Basics textbook, you learned a lot about the way the mudlib + works, specifically in relation to objects you code in order to build your + realm. Not much was discussed about the interaction between the + mudlib and the driver. You should know, however, that the driver + does the following: + 1) When an object is first loaded into memory, the driver will call + create() in native muds and reset() in compat muds. A creator + uses create() or reset() to give initial values to the object. + 2) At an interval setup by the game administrator, the driver calls the + function reset(). This allows the object to regenerate monsters and + such. Notice that in a compat mud, the same function is used to set up + initial values as is used to reset the room. + 3) Any time a living object comes in contact with an object of any sort, + the driver calls init() in the newly encountered object. This allows + newly encountered objects to give living objects commands to execute + through the add_action() efun, as well as perform other actions which + should happen whenever a living thing encounters a given object. + 4) The driver defines a set of functions known as efuns which are + available to all objects in the game. Examples of commonly used efuns + are: this_player(), this_object(), write(), say(), etc. + + 2.2 The Driver Cycle + The driver is a C program which runs the game. Its basic functions are + to accept connections from the outside world so people can login, + interpret the LPC code which defines LPC objects and how they + function in the game, and accept user input and call the appropriate LPC + functions which match the event. In its most simplest essence, it is an + unending loop. + + Once the game has booted up and is properly functioning (the boot up + process will be discussed in a future, advanced LPC textbook), the + driver enters a loop which does not terminate until the shutdown() efun + is legally called or a bug causes the driver program to crash. First off, + the driver handles any new incoming connections and passes control of + the connection to a login object. After that, the driver puts together a + table of commands which have been entered by users since the last cycle + of the driver. After the command table is assembled, all messages + scheduled to be sent to the connection from the last driver cycle are sent + out to the user. At this point, the driver goes through the table of + commands to be executed and executes each set of commands each + object has stored there. The driver ends its cycle by calling the function + heart_beat() in every object with a heart_beat() set and finally + performing all pending call outs. This chapter will not deal with the + handling of connections, but instead will focus on how the driver + handles user commands and heartbeats and call outs. + + 2.3 User Commands + As noted in section 1.2, the driver stores a list of commands for each + user to be executed each cycle. The commands list has the name of the + living object performing the command, the object which gave the living + object that command, and the function which is to be executed in order + to perform the command. The driver refers to the object which typed in + the command as the command giver. It is the command giver which + gets returned as this_player() in most cases. + + The driver starts at the top of the list of living objects with pending + commands, and successively performs each command it typed by calling + the function associated with the command and passing any arguments + the command giver gave as arguments to the function. As the driver + starts with the commands issued by a new living object, the command + giver variable is changed to be equal to the new living object, so that + during the sequence of functions initiated by that command, the efun + this_player() returns the object which issued the command. + + Let's look at the command buffer for an example player. Since the + execution of his last command, Bozo has typed "north" and "tell + descartes when is the next reboot". The command "north" is associated + with the function "Do_Move()" in the room Bozo is in (the command + "north" is automatically setup by the SetExits() efun in that room). The + command "tell" is not specifically listed as a command for the player, + however, in the player object there is a function called "cmd_hook()" + which is associated with the command "", which matches any possible + user input. + + Once the driver gets down to Bozo, the command giver variable is set to + the object which is Bozo. Then, seeing Bozo typed "north" and the + function "north" is associated with, the driver calls Bozo's_Room- + >Do_Move(0). An argument of 0 is passed to the function since Bozo + only typed the command "north" with no arguments. The room + naturally calls some functions it needs, all the while such that the efun + this_player() returns the object which is Bozo. Eventually, the room + object will call eventMoveLiving() in Bozo, which in turn calls the + move_object() efun. This efun is responsible for changing an object's + environment. + + When the environment of an object changes, the commands available to + it from objects in its previous environment as well as from its previous + environment are removed from the object. Once that is done, the driver + calls the efun init() in the new environment as well as in each object in + the new environment. During each of these calls to init(), the object + Bozo is still the command giver. Thus all add_action() efuns from this + move will apply to Bozo. Once all those calls are done, control passes + back from the move_object() efun to the eventMoveLiving() lfun in Bozo. + eventMoveLiving() returns control back to Do_Move() in the old room, + which returns 1 to signify to the driver that the command action was + successful. If the Do_Move() function had returned 0 for some reason, + the driver would have written "What?" (or whatever your driver's + default bad command message is) to Bozo. + + Once the first command returns 1, the driver proceeds on to Bozo's + second command, following much the same structure. Note that with + "tell descartes when is the next reboot", the driver passes "descartes + when is the next reboot" to the function associated with tell. That + function in turn has to decide what to do with that argument. After that + command returns either 1 or 0, the driver then proceeds on to the next + living object with commands pending, and so on until all living objects + with pending commands have had their commands performed. + + 2.4 The Efuns set_heart_beat() and call_out() + Once all commands are performed for objects with commands pending, + the driver then proceeds to call the heart_beat() function in all objects + listed with the driver as having heartbeats. Whenever an object calls the + efun set_heart_beat() with a non-zero argument (depending on your + driver, what non-zero number may be important, but in most cases you + call it with the int 1). The efun set_heart_beat() adds the object which + calls set_heart_beat() to the list of objects with heartbeats. If you call it + with an argument of 0, then it removes the object from the list of objects + with heartbeats. + + The most common use for heartbeats in the mudlib is to heal players and + monsters and perform combat. Once the driver has finished dealing with + the command list, it goes through the heartbeat list calling heart_beat() in + each object in the list. So for a player, for example, the driver will call + heart_beat() in the player which will: + 1) age the player + 2) heal the player according to a heal rate + 3) check to see if there are any hunted, hunting, or attacking objects + around + 4) perform an attack if step 3 returns true. + 5) any other things which need to happen automatically roughly every + second + + Note that the more objects which have heartbeats, the more processing + which has to happen every cycle the mud is up. Objects with heartbeats + are thus known as the major hog of CPU time on muds. + + The call_out() efun is used to perform timed function calls which do not + need to happen as often as heartbeats, or which just happen once. Call + outs let you specify the function in an object you want called. The + general formula for call outs is: + call_out(func, time, args); + The third argument specifying arguments is optional. The first argument + is a string representing the name of the function to be called. The second + argument is how many seconds should pass before the function gets + called. + + Practically speaking, when an object calls call_out(), it is added to a list + of objects with pending call outs with the amount of time of the call out + and the name of the function to be called. Each cycle of the driver, the + time is counted down until it becomes time for the function to be called. + When the time comes, the driver removes the object from the list of + objects with pending call outs and performs the call to the call out + function, passing any special args originally specified by the call out + function. + + If you want a to remove a pending call before it occurs, you need to use + the remove_call_out() efun, passing the name of the function being + called out. The driver will remove the next pending call out to that + function. This means you may have some ambiguity if more than one + call out is pending for the same function. + + In order to make a call out cyclical, you must reissue the call_out() efun + in the function you called out, since the driver automatically removes the + function from the call out table when a call out is performed. Example: + + void foo() { call_out("hello", 10); } + + void hello() { call_out("hello", 10); } + + will set up hello() to be called every 10 seconds after foo() is first called. + There are several things to be careful about here. First, you must watch + to make sure you do not structure your call outs to be recursive in any + unintended fashion. Second, compare what a set_heart_beat() does + when compared directly to what call_out() does. + + set_heart_beat(): + a) Adds this_object() to a table listing objects with heartbeats. + b) The function heart_beat() in this_object() gets called every single + driver cycle. + + call_out(): + a) Adds this_object(), the name of a function in this_object(), a time + delay, and a set of arguments to a table listing functions with pending + call outs. + b) The function named is called only once, and that call comes after the + specified delay. + + As you can see, there is a much greater memory overhead associated + with call outs for part (a), yet that there is a much greater CPU overhead + associated with heartbeats as shown in part (b), assuming that the delay + for the call out is greater than a single driver cycle. + + Clearly, you do not want to be issuing 1 second call outs, for then you + get the worst of both worlds. Similarly, you do not want to be having + heart beats in objects that can perform the same functions with call outs + of a greater duration than 1 second. I personally have heard much talk + about at what point you should use a call out over a heartbeat. What I + have mostly heard is that for single calls or for cycles of a duration + greater than 10 seconds, it is best to use a call out. For repetitive calls of + durations less than 10 seconds, you are better off using heartbeats. I do + not know if this is true, but I do not think following this can do any + harm. + + 2.5 Summary + Basic to a more in depth understanding of LPC is and understanding of + the way in which the driver interacts with the mudlib. You should now + understand the order in which the driver performs functions, as well as a + more detailed knowledge of the efuns this_player(), add_action(), and + move_object() and the lfun init(). In addition to this building upon + knowledge you got from the LPC Basics textbook, this chapter has + introduced call outs and heartbeats and the manner in which the driver + handles them. You should now have a basic understanding of call outs + and heartbeats such that you can experiment with them in your realm + code. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/manual/chapter11 ds2.1/lib/doc/manual/chapter11 *** ds1.1/lib/doc/manual/chapter11 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter11 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,477 ---- + chapter 11 "Complex Data Types" + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 3: Complex Data Types + + 3.1 Simple Data Types + In the textbook LPC Basics, you learned about the common, basic LPC + data types: int, string, object, void. Most important you learned that + many operations and functions behave differently based on the data type + of the variables upon which they are operating. Some operators and + functions will even give errors if you use them with the wrong data + types. For example, "a"+"b" is handled much differently than 1+1. + When you ass "a"+"b", you are adding "b" onto the end of "a" to get + "ab". On the other hand, when you add 1+1, you do not get 11, you get + 2 as you would expect. + + I refer to these data types as simple data types, because they atomic in + that they cannot be broken down into smaller component data types. + The object data type is a sort of exception, but you really cannot refer + individually to the components which make it up, so I refer to it as a + simple data type. + + This chapter introduces the concept of the complex data type, a data type + which is made up of units of simple data types. LPC has two common + complex data types, both kinds of arrays. First, there is the traditional + array which stores values in consecutive elements accessed by a number + representing which element they are stored in. Second is an associative + array called a mapping. A mapping associates to values together to + allow a more natural access to data. + + 3.2 The Values NULL and 0 + Before getting fully into arrays, there first should be a full understanding + of the concept of NULL versus the concept of 0. In LPC, a null value is + represented by the integer 0. Although the integer 0 and NULL are often + freely interchangeable, this interchangeability often leads to some great + confusion when you get into the realm of complex data types. You may + have even encountered such confusion while using strings. + + 0 represents a value which for integers means the value you add to + another value yet still retain the value added. This for any addition + operation on any data type, the ZERO value for that data type is the value + that you can add to any other value and get the original value. Thus: A + plus ZERO equals A where A is some value of a given data type and + ZERO is the ZERO value for that data type. This is not any sort of + official mathematical definition. There exists one, but I am not a + mathematician, so I have no idea what the term is. Thus for integers, 0 + is the ZERO value since 1 + 0 equals 1. + + NULL, on the other hand, is the absence of any value or meaning. The + LPC driver will interpret NULL as an integer 0 if it can make sense of it + in that context. In any context besides integer addition, A plus NULL + causes an error. NULL causes an error because adding valueless fields + in other data types to those data types makes no sense. + + Looking at this from another point of view, we can get the ZERO value + for strings by knowing what added to "a" will give us "a" as a result. + The answer is not 0, but instead "". With integers, interchanging NULL + and 0 was acceptable since 0 represents no value with respect to the + integer data type. This interchangeability is not true for other data types, + since their ZERO values do not represent no value. Namely, "" + represents a string of no length and is very different from 0. + + When you first declare any variable of any type, it has no value. Any + data type except integers therefore must be initialized somehow before + you perform any operation on it. Generally, initialization is done in the + create() function for global variables, or at the top of the local function + for local variables by assigning them some value, often the ZERO value + for that data type. For example, in the following code I want to build a + string with random words: + + string build_nonsense() { + string str; + int i; + + str = ""; /* Here str is initialized to the string + ZERO value */ + for(i=0; i<6; i++) { + switch(random(3)+1) { + case 1: str += "bing"; break; + case 2: str += "borg"; break; + case 3: str += "foo"; break; + } + if(i==5) str += ".\n"; + else str += " "; + } + return capitalize(str); + } + + If we had not initialized the variable str, an error would have resulted + from trying to add a string to a NULL value. Instead, this code first + initializes str to the ZERO value for strings, "". After that, it enters a + loop which makes 6 cycles, each time randomly adding one of three + possible words to the string. For all words except the last, an additional + blank character is added. For the last word, a period and a return + character are added. The function then exits the loop, capitalizes the + nonsense string, then exits. + + 3.3 Arrays in LPC + An array is a powerful complex data type of LPC which allows you to + access multiple values through a single variable. For instance, + Nightmare has an indefinite number of currencies in which players may + do business. Only five of those currencies, however, can be considered + hard currencies. A hard currency for the sake of this example is a + currency which is readily exchangeable for any other hard currency, + whereas a soft currency may only be bought, but not sold. In the bank, + there is a list of hard currencies to allow bank keepers to know which + currencies are in fact hard currencies. With simple data types, we would + have to perform the following nasty operation for every exchange + transaction: + + int exchange(string str) { + string from, to; + int amt; + + if(!str) return 0; + if(sscanf(str, "%d %s for %s", amt, from, to) != 3) + return 0; + if(from != "platinum" && from != "gold" && from != + "silver" && + from != "electrum" && from != "copper") { + notify_fail("We do not buy soft currencies!\n"); + return 0; + } + ... + } + + With five hard currencies, we have a rather simple example. After all it + took only two lines of code to represent the if statement which filtered + out bad currencies. But what if you had to check against all the names + which cannot be used to make characters in the game? There might be + 100 of those; would you want to write a 100 part if statement? + What if you wanted to add a currency to the list of hard currencies? That + means you would have to change every check in the game for hard + currencies to add one more part to the if clauses. Arrays allow you + simple access to groups of related data so that you do not have to deal + with each individual value every time you want to perform a group + operation. + + As a constant, an array might look like this: + ({ "platinum", "gold", "silver", "electrum", "copper" }) + which is an array of type string. Individual data values in arrays are + called elements, or sometimes members. In code, just as constant + strings are represented by surrounding them with "", constant arrays are + represented by being surrounded by ({ }), with individual elements of + the array being separated by a ,. + + You may have arrays of any LPC data type, simple or complex. Arrays + made up of mixes of values are called arrays of mixed type. In most + LPC drivers, you declare an array using a throw-back to C language + syntax for arrays. This syntax is often confusing for LPC coders + because the syntax has a meaning in C that simply does not translate into + LPC. Nevertheless, if we wanted an array of type string, we would + declare it in the following manner: + + string *arr; + + In other words, the data type of the elements it will contain followed by + a space and an asterisk. Remember, however, that this newly declared + string array has a NULL value in it at the time of declaration. + + 3.4 Using Arrays + You now should understand how to declare and recognize an array in + code. In order to understand how they work in code, let's review the + bank code, this time using arrays: + + string *hard_currencies; + + int exchange(string str) { + string from, to; + int amt; + + if(!str) return 0; + if(sscanf(str, "%d %s for %s", amt, from, to) != 3) + return 0; + if(member_array(from, hard_currencies) == -1) { + notify_fail("We do not buy soft currencies!\n"); + return 0; + } + ... + } + + This code assumes hard_currencies is a global variable and is initialized + in create() as: + hard_currencies = ({ "platinum", "gold", "electrum", "silver", + "copper" }); + Ideally, you would have hard currencies as a #define in a header file for + all objects to use, but #define is a topic for a later chapter. + + Once you know what the member_array() efun does, this method + certainly is much easier to read as well as is much more efficient and + easier to code. In fact, you can probably guess what the + member_array() efun does: It tells you if a given value is a member of + the array in question. Specifically here, we want to know if the currency + the player is trying to sell is an element in the hard_curencies array. + What might be confusing to you is, not only does member_array() tell us + if the value is an element in the array, but it in fact tells us which element + of the array the value is. + + How does it tell you which element? It is easier to understand arrays if + you think of the array variable as holding a number. In the value above, + for the sake of argument, we will say that hard_currencies holds the + value 179000. This value tells the driver where to look for the array + hard_currencies represents. Thus, hard_currencies points to a place + where the array values may be found. When someone is talking about + the first element of the array, they want the element located at 179000. + When the object needs the value of the second element of the array, it + looks at 179000 + one value, then 179000 plus two values for the third, + and so on. We can therefore access individual elements of an array by + their index, which is the number of values beyond the starting point of + the array we need to look to find the value. For the array + hard_currencies array: + "platinum" has an index of 0. + "gold" has an index of 1. + "electrum" has an index of 2. + "silver" has an index of 3. + "copper" has an index of 4. + + The efun member_array() thus returns the index of the element being + tested if it is in the array, or -1 if it is not in the array. In order to + reference an individual element in an array, you use its index number in + the following manner: + array_name[index_no] + Example: + hard_currencies[3] + where hard_currencies[3] would refer to "silver". + + So, you now should now several ways in which arrays appear either as + a whole or as individual elements. As a whole, you refer to an array + variable by its name and an array constant by enclosing the array in ({ }) + and separating elements by ,. Individually, you refer to array variables + by the array name followed by the element's index number enclosed in + [], and to array constants in the same way you would refer to simple data + types of the same type as the constant. Examples: + + Whole arrays: + variable: arr + constant: ({ "platinum", "gold", "electrum", "silver", "copper" }) + + Individual members of arrays: + variable: arr[2] + constant: "electrum" + + You can use these means of reference to do all the things you are used to + doing with other data types. You can assign values, use the values in + operations, pass the values as parameters to functions, and use the + values as return types. It is important to remember that when you are + treating an element alone as an individual, the individual element is not + itself an array (unless you are dealing with an array of arrays). In the + example above, the individual elements are strings. So that: + str = arr[3] + " and " + arr[1]; + will create str to equal "silver and gold". Although this seems simple + enough, many people new to arrays start to run into trouble when trying + to add elements to an array. When you are treating an array as a whole + and you wish to add a new element to it, you must do it by adding + another array. + + Note the following example: + string str1, str2; + string *arr; + + str1 = "hi"; + str2 = "bye"; + /* str1 + str2 equals "hibye" */ + arr = ({ str1 }) + ({ str2 }); + /* arr is equal to ({ str1, str2 }) */ + Before going any further, I have to note that this example gives an + extremely horrible way of building an array. You should set it: arr = ({ + str1, str2 }). The point of the example, however, is that you must add + like types together. If you try adding an element to an array as the data + type it is, you will get an error. Instead you have to treat it as an array of + a single element. + + 3.5 Mappings + One of the major advances made in LPMuds since they were created is + the mapping data type. People alternately refer to them as associative + arrays. Practically speaking, a mapping allows you freedom from the + association of a numerical index to a value which arrays require. + Instead, mappings allow you to associate values with indices which + actually have meaning to you, much like a relational database. + + In an array of 5 elements, you access those values solely by their integer + indices which cover the range 0 to 4. Imagine going back to the example + of money again. Players have money of different amounts and different + types. In the player object, you need a way to store the types of money + that exist as well as relate them to the amount of that currency type the + player has. The best way to do this with arrays would have been to + store an array of strings representing money types and an array of + integers representing values in the player object. This would result in + CPU-eating ugly code like this: + + int query_money(string type) { + int i; + + i = member_array(type, currencies); + if(i>-1 && i < sizeof(amounts)) /* sizeof efun + returns # of elements */ + return amounts[i]; + else return 0; + } + + And that is a simple query function. Look at an add function: + + void add_money(string type, int amt) { + string *tmp1; + int * tmp2; + int i, x, j, maxj; + + i = member_array(type, currencies); + if(i >= sizeof(amounts)) /* corrupt data, we are in + a bad way */ + return; + else if(i== -1) { + currencies += ({ type }); + amounts += ({ amt }); + return; + } + else { + amounts[i] += amt; + if(amounts[i] < 1) { + tmp1 = allocate(sizeof(currencies)-1); + tmp2 = allocate(sizeof(amounts)-1); + for(j=0, x =0, maxj=sizeof(tmp1); j < maxj; + j++) { + if(j==i) x = 1; + tmp1[j] = currencies[j+x]; + tmp2[j] = amounts[j+x]; + } + currencies = tmp1; + amounts = tmp2; + } + } + } + + That is really some nasty code to perform the rather simple concept of + adding some money. First, we figure out if the player has any of that + kind of money, and if so, which element of the currencies array it is. + After that, we have to check to see that the integrity of the currency data + has been maintained. If the index of the type in the currencies array is + greater than the highest index of the amounts array, then we have a + problem since the indices are our only way of relating the two arrays. + Once we know our data is in tact, if the currency type is not currently + held by the player, we simply tack on the type as a new element to the + currencies array and the amount as a new element to the amounts array. + Finally, if it is a currency the player currently has, we just add the + amount to the corresponding index in the amounts array. If the money + gets below 1, meaning having no money of that type, we want to clear + the currency out of memory. + + Subtracting an element from an array is no simple matter. Take, for + example, the result of the following: + + string *arr; + + arr = ({ "a", "b", "a" }); + arr -= ({ arr[2] }); + + What do you think the final value of arr is? Well, it is: + ({ "b", "a" }) + Subtracting arr[2] from the original array does not remove the third + element from the array. Instead, it subtracts the value of the third + element of the array from the array. And array subtraction removes the + first instance of the value from the array. Since we do not want to be + forced on counting on the elements of the array as being unique, we are + forced to go through some somersaults to remove the correct element + from both arrays in order to maintain the correspondence of the indices + in the two arrays. + + Mappings provide a better way. They allow you to directly associate the + money type with its value. Some people think of mappings as arrays + where you are not restricted to integers as indices. Truth is, mappings + are an entirely different concept in storing aggregate information. Arrays + force you to choose an index which is meaningful to the machine for + locating the appropriate data. The indices tell the machine how many + elements beyond the first value the value you desire can be found. With + mappings, you choose indices which are meaningful to you without + worrying about how that machine locates and stores it. + + You may recognize mappings in the following forms: + + constant values: + whole: ([ index:value, index:value ]) Ex: ([ "gold":10, "silver":20 ]) + element: 10 + + variable values: + whole: map (where map is the name of a mapping variable) + element: map["gold"] + + So now my monetary functions would look like: + + int query_money(string type) { return money[type]; } + + void add_money(string type, int amt) { + if(!money[type]) money[type] = amt; + else money[type] += amt; + if(money[type] < 1) + map_delete(money, type); /* this is for + MudOS */ + ...OR... + money = m_delete(money, type) /* for some + LPMud 3.* varieties */ + ... OR... + m_delete(money, type); /* for other LPMud 3.* + varieties */ + } + + Please notice first that the efuns for clearing a mapping element from the + mapping vary from driver to driver. Check with your driver's + documentation for the exact name an syntax of the relevant efun. + + As you can see immediately, you do not need to check the integrity of + your data since the values which interest you are inextricably bound to + one another in the mapping. Secondly, getting rid of useless values is a + simple efun call rather than a tricky, CPU-eating loop. Finally, the + query function is made up solely of a return instruction. + + You must declare and initialize any mapping before using it. + Declarations look like: + mapping map; + Whereas common initializations look like: + map = ([]); + map = allocate_mapping(10) ...OR... map = m_allocate(10); + map = ([ "gold": 20, "silver": 15 ]); + + As with other data types, there are rules defining how they work in + common operations like addition and subtraction: + ([ "gold":20, "silver":30 ]) + ([ "electrum":5 ]) + gives: + (["gold":20, "silver":30, "electrum":5]) + Although my demonstration shows a continuity of order, there is in fact + no guarantee of the order in which elements of mappings will stored. + Equivalence tests among mappings are therefore not a good thing. + + 3.6 Summary + Mappings and arrays can be built as complex as you need them to be. + You can have an array of mappings of arrays. Such a thing would be + declared like this: + + mapping *map_of_arrs; + which might look like: + ({ ([ ind1: ({ valA1, valA2}), ind2: ({valB1, valB2}) ]), ([ indX: + ({valX1,valX2}) ]) }) + + Mappings may use any data type as an index, including objects. + Mapping indices are often referred to as keys as well, a term from + databases. Always keep in mind that with any non-integer data type, + you must first initialize a variable before making use of it in common + operations such as addition and subtraction. In spite of the ease and + dynamics added to LPC coding by mappings and arrays, errors caused + by failing to initialize their values can be the most maddening experience + for people new to these data types. I would venture that a very high + percentage of all errors people experimenting with mappings and arrays + for the first time encounter are one of three error messages: + Indexing on illegal type. + Illegal index. + Bad argument 1 to (+ += - -=) /* insert your favourite operator */ + Error messages 1 and 3 are darn near almost always caused by a failure + to initialize the array or mapping in question. Error message 2 is caused + generally when you are trying to use an index in an initialized array + which does not exist. Also, for arrays, often people new to arrays will + get error message 3 because they try to add a single element to an array + by adding the initial array to the single element value instead of adding + an array of the single element to the initial array. Remember, add only + arrays to arrays. + + At this point, you should feel comfortable enough with mappings and + arrays to play with them. Expect to encounter the above error messages + a lot when first playing with these. The key to success with mappings is + in debugging all of these errors and seeing exactly what causes wholes + in your programming which allow you to try to work with uninitialized + mappings and arrays. Finally, go back through the basic room code and + look at things like the SetExits() (or the equivalent on your mudlib) + function. Chances are it makes use of mappings. In some instances, it + will use arrays as well for compatibility with mudlib.n. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/manual/chapter12 ds2.1/lib/doc/manual/chapter12 *** ds1.1/lib/doc/manual/chapter12 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter12 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,183 ---- + chapter 12 "The LPC Pre-Compiler" + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 4: The LPC Pre-Compiler + + 4.1 Review + The previous chapter was quite heavy, so now I will slow down a bit so + you can digest and play with mappings and arrays by taking on the + rather simple topic of the LPC pre-compiler. By this point, however, + you should well understand how the driver interacts with the mudlib and + be able to code objects which use call outs and heart beats. In addition, + you should be coding simple objects which use mappings and arrays, + noting how these data types perform in objects. It is also a good idea to + start looking in detail at the actual mudlib code that makes up your mud. + See if you understand everything which is going on in your mudlibs + room and monster codes. For things you do not understand, ask the + people on your mud designated to answer creator coding questions. + + Pre-compiler is actually a bit of a misnomer since LPC code is never + truly compiled. Although this is changing with prototypes of newer + LPC drivers, LPC drivers interpret the LPC code written by creators + rather than compile it into binary format. Nevertheless, the LPC pre- + compiler functions still perform much like pre-compilers for compiled + languages in that pre-compiler directives are interpreted before the driver + even starts to look at object code. + + 4.2 Pre-compiler Directives + If you do not know what a pre-compiler is, you really do not need to + worry. With respect to LPC, it is basically a process which happens + before the driver begins to interpret LPC code which allows you to + perform actions upon the entire code found in your file. Since the code + is not yet interpreted, the pre-compiler process is involved before the file + exists as an object and before any LPC functions or instructions are ever + examined. The pre-compiler is thus working at the file level, meaning + that it does not deal with any code in inherited files. + + The pre-compiler searches a file sent to it for pre-compiler directives. + These are little instructions in the file meant only for the pre-compiler + and are not really part of the LPC language. A pre-compiler directive is + any line in a file beginning with a pound (#) sign. Pre-compiler + directives are generally used to construct what the final code of a file will + look at. The most common pre-compiler directives are: + + #define + #undefine + #include + #ifdef + #ifndef + #if + #elseif + #else + #endif + #pragma + + Most realm coders on muds use exclusively the directives #define and + #include. The other directives you may see often and should understand + what they mean even if you never use them. + + The first pair of directives are: + #define + #undefine + + The #define directive sets up a set of characters which will be replaced + any where they exist in the code at precompiler time with their definition. + For example, take: + + #define OB_USER "/std/user" + + This directive has the pre-compiler search the entire file for instances of + OB_USER. Everywhere it sees OB_USER, it replaces with "/std/user". + Note that it does not make OB_USER a variable in the code. The LPC + interpreter never sees the OB_USER label. As stated above, the pre- + compiler is a process which takes place before code interpretation. So + what you wrote as: + + #define OB_USER "/std/user" + + void create() { + if(!file_exists(OB_USER+".c")) write("Merde! No user file!"); + else write("Good! User file still exists!"); + } + + would arrive at the LPC interpreter as: + + void create() { + if(!file_exists("/std/user"+".c")) write("Merde! No user file!"); + else write("Good! User file still exists!"); + } + + Simply put, #define just literally replaces the defined label with whatever + follows it. You may also use #define in a special instance where no + value follows. This is called a binary definition. For example: + + #define __NIGHTMARE + + exists in the config file for the Nightmare Mudlib. This allows for pre- + compiler tests which will be described later in the chapter. + + The other pre-compiler directive you are likely to use often is #include. + As the name implies, #include includes the contents of another file right + into the file being pre-compiled at the point in the file where the directive + is placed. Files made for inclusion into other files are often called header + files. They sometimes contain things like #define directives used by + multiple files and function declarations for the file. The traditional file + extension to header files is .h. + + Include directives follow one of 2 syntax's: + + #include <filename> + #include "filename" + + If you give the absolute name of the file, then which syntax you use is + irrelevant. How you enclose the file name determines how the pre- + compiler searches for the header files. The pre-compiler first searches in + system include directories for files enclosed in <>. For files enclosed in + "", the pre-compiler begins its search in the same directory as the file + going through the pre-compiler. Either way, the pre-compiler will + search the system include directories and the directory of the file for the + header file before giving up. The syntax simply determines the order. + + The simplest pre-compiler directive is the #pragma directive. It is + doubtful you will ever use this one. Basically, you follow the directive + with some keyword which is meaningful to your driver. The only + keyword I have ever seen is strict_types, which simply lets the driver + know you want this file interpreted with strict data typing. I doubt you + will ever need to use this, and you may never even see it. I just included + it in the list in the event you do see it so you do not think it is doing + anything truly meaningful. + + The final group of pre-compiler directives are the conditional pre- + compiler directives. They allow you to pre-compile the file one way + given the truth value of an expression, otherwise pre-compile the file + another way. This is mostly useful for making code portable among + mudlibs, since putting the m_delete() efun in code on a MudOS mud + would normally cause an error, for example. So you might write the + following: + + #ifdef MUDOS + map_delete(map, key); + #else + map = m_delete(map, key); + #endif + + which after being passed through the pre-compiler will appear to the + interpreter as: + + map_delete(map, key); + + on a MudOS mud, and: + + map = m_delete(map, key); + + on other muds. The interpreter never sees the function call that would + cause it to spam out in error. + + Notice that my example made use of a binary definition as described + above. Binary definitions allow you to pass certain code to the + interpreter based on what driver or mudlib you are using, among other + conditions. + + 4.3 Summary + The pre-compiler is a useful LPC tool for maintaining modularity among + your programs. When you have values that might be subject to change, + but are used widely throughout your files, you might stick all of those + values in a header file as #define statements so that any need to make a + future change will cause you to need to change just the #define directive. + A very good example of where this would be useful would be a header + file called money.h which includes the directive: + #define HARD_CURRENCIES ({ "gold", "platinum", "silver", + "electrum", "copper" }) + so that if ever you wanted to add a new hard currency, you only need + change this directive in order to update all files needing to know what the + hard currencies are. + + The LPC pre-compiler also allows you to write code which can be + ported without change among different mudlibs and drivers. Finally, + you should be aware that the pre-compiler only accepts lines ending in + carriage returns. If you want a multiple line pre-compiler directive, you + need to end each incomplete line with a backslash(\). + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/manual/chapter13 ds2.1/lib/doc/manual/chapter13 *** ds1.1/lib/doc/manual/chapter13 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter13 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,182 ---- + chapter 13 "Advanced String Handling" + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 5: Advanced String Handling + + 5.1 What a String Is + The LPC Basics textbook taught strings as simple data types. LPC + generally deals with strings in such a matter. The underlying driver + program, however, is written in C, which has no string data type. The + driver in fact sees strings as a complex data type made up of an array of + characters, a simple C data type. LPC, on the other hand does not + recognize a character data type (there may actually be a driver or two out + there which do recognize the character as a data type, but in general not). + The net effect is that there are some array-like things you can do with + strings that you cannot do with other LPC data types. + + The first efun regarding strings you should learn is the strlen() efun. + This efun returns the length in characters of an LPC string, and is thus + the string equivalent to sizeof() for arrays. Just from the behaviour of + this efun, you can see that the driver treats a string as if it were made up + of smaller elements. In this chapter, you will learn how to deal with + strings on a more basic level, as characters and sub strings. + + 5.2 Strings as Character Arrays + You can do nearly anything with strings that you can do with arrays, + except assign values on a character basis. At the most basic, you can + actually refer to character constants by enclosing them in '' (single + quotes). 'a' and "a" are therefore very different things in LPC. 'a' + represents a character which cannot be used in assignment statements or + any other operations except comparison evaluations. "a" on the other + hand is a string made up of a single character. You can add and subtract + other strings to it and assign it as a value to a variable. + + With string variables, you can access the individual characters to run + comparisons against character constants using exactly the same syntax + that is used with arrays. In other words, the statement: + if(str[2] == 'a') + is a valid LPC statement comparing the second character in the str string + to the character 'a'. You have to be very careful that you are not + comparing elements of arrays to characters, nor are you comparing + characters of strings to strings. + + LPC also allows you to access several characters together using LPC's + range operator ..: + if(str[0..1] == "ab") + In other words, you can look for the string which is formed by the + characters 0 through 1 in the string str. As with arrays, you must be + careful when using indexing or range operators so that you do not try to + reference an index number larger than the last index. Doing so will + result in an error. + + Now you can see a couple of similarities between strings and arrays: + 1) You may index on both to access the values of individual elements. + a) The individual elements of strings are characters + b) The individual elements of arrays match the data type of the + array. + 2) You may operate on a range of values + a) Ex: "abcdef"[1..3] is the string "bcd" + b) Ex: ({ 1, 2, 3, 4, 5 })[1..3] is the int array ({ 2, 3, 4 }) + + And of course, you should always keep in mind the fundamental + difference: a string is not made up of a more fundamental LPC data type. + In other words, you may not act on the individual characters by + assigning them values. + + 5.3 The Efun sscanf() + You cannot do any decent string handling in LPC without using + sscanf(). Without it, you are left trying to play with the full strings + passed by command statements to the command functions. In other + words, you could not handle a command like: "give sword to leo", since + you would have no way of separating "sword to leo" into its constituent + parts. Commands such as these therefore use this efun in order to use + commands with multiple arguments or to make commands more + "English-like". + + Most people find the manual entries for sscanf() to be rather difficult + reading. The function does not lend itself well to the format used by + manual entries. As I said above, the function is used to take a string and + break it into usable parts. Technically it is supposed to take a string and + scan it into one or more variables of varying types. Take the example + above: + + int give(string str) { + string what, whom; + + if(!str) return notify_fail("Give what to whom?\n"); + if(sscanf(str, "%s to %s", what, whom) != 2) + return notify_fail("Give what to whom?\n"); + ... rest of give code ... + } + + The efun sscanf() takes three or more arguments. The first argument is + the string you want scanned. The second argument is called a control + string. The control string is a model which demonstrates in what form + the original string is written, and how it should be divided up. The rest + of the arguments are variables to which you will assign values based + upon the control string. + + The control string is made up of three different types of elements: 1) + constants, 2) variable arguments to be scanned, and 3) variable + arguments to be discarded. You must have as many of the variable + arguments in sscanf() as you have elements of type 2 in your control + string. In the above example, the control string was "%s to %s", which + is a three element control string made up of one constant part (" to "), + and two variable arguments to be scanned ("%s"). There were no + variables to be discarded. + + The control string basically indicates that the function should find the + string " to " in the string str. Whatever comes before that constant will + be placed into the first variable argument as a string. The same thing + will happen to whatever comes after the constant. + + Variable elements are noted by a "%" sign followed by a code for + decoding them. If the variable element is to be discarded, the "%" sign + is followed by the "*" as well as the code for decoding the variable. + Common codes for variable element decoding are "s" for strings and "d" + for integers. In addition, your mudlib may support other conversion + codes, such as "f" for float. So in the two examples above, the "%s" in + the control string indicates that whatever lies in the original string in the + corresponding place will be scanned into a new variable as a string. + + A simple exercise. How would you turn the string "145" into an + integer? + + Answer: + int x; + sscanf("145", "%d", x); + + After the sscanf() function, x will equal the integer 145. + + Whenever you scan a string against a control string, the function + searches the original string for the first instance of the first constant in + the original string. For example, if your string is "magic attack 100" and + you have the following: + int improve(string str) { + string skill; + int x; + + if(sscanf(str, "%s %d", skill, x) != 2) return 0; + ... + } + you would find that you have come up with the wrong return value for + sscanf() (more on the return values later). The control string, "%s %d", + is made up of to variables to be scanned and one constant. The constant + is " ". So the function searches the original string for the first instance + of " ", placing whatever comes before the " " into skill, and trying to + place whatever comes after the " " into x. This separates "magic attack + 100" into the components "magic" and "attack 100". The function, + however, cannot make heads or tales of "attack 100" as an integer, so it + returns 1, meaning that 1 variable value was successfully scanned + ("magic" into skill). + + Perhaps you guessed from the above examples, but the efun sscanf() + returns an int, which is the number of variables into which values from + the original string were successfully scanned. Some examples with + return values for you to examine: + + sscanf("swo rd descartes", "%s to %s", str1, str2) return: 0 + sscanf("swo rd descartes", "%s %s", str1, str2) return: 2 + sscanf("200 gold to descartes", "%d %s to %s", x, str1, str2) return: 3 + sscanf("200 gold to descartes", "%d %*s to %s", x, str1) return: 2 + where x is an int and str1 and str2 are string + + 5.4 Summary + LPC strings can be thought of as arrays of characters, yet always + keeping in mind that LPC does not have the character data type (with + most, but not all drivers). Since the character is not a true LPC data + type, you cannot act upon individual characters in an LPC string in the + same manner you would act upon different data types. Noticing the + intimate relationship between strings and arrays nevertheless makes it + easier to understand such concepts as the range operator and indexing on + strings. + + There are efuns other than sscanf() which involve advanced string + handling, however, they are not needed nearly as often. You should + check on your mud for man or help files on the efuns: explode(), + implode(), replace_string(), sprintf(). All of these are very valuable + tools, especially if you intend to do coding at the mudlib level. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/manual/chapter14 ds2.1/lib/doc/manual/chapter14 *** ds1.1/lib/doc/manual/chapter14 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter14 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,277 ---- + chapter 14 "Intermediate Inheritance" + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 6: Intermediate Inheritance + + 6.1 Basics of Inheritance + In the textbook LPC Basics, you learned how it is the mudlib maintains + consistency amoung mud objects through inheritance. Inheritance + allows the mud administrators to code the basic functions and such that + all mudlib objects, or all mudlib objects of a certain type must have so + that you can concentrate on creating the functions which make these + objects different. When you build a room, or a weapon, or a monster, + you are taking a set of functions already written for you and inheriting + them into your object. In this way, all objects on the mud can count on + other objects to behave in a certain manner. For instance, player objects + can rely on the fact that all room objects will have a function in them + called GetLong() which describes the room. Inheritance thus keeps + you from having to worry about what the function GetLong() should + look like. + + Naturally, this textbook tries to go beyond this fundamental knowledge + of inheritance to give the coder a better undertstanding of how + inheritance works in LPC programming. Without getting into detail that + the advanced domain coder/beginner mudlib coder simply does not yet + need, this chapter will try to explain exactly what happens when you + inherit an object. + + 6.2 Cloning and Inheritance + Whenever a file is referenced for the first time as an object (as opposed + to reading the contents of the file), the game tries to load the file into + memory and create an object. If the object is successfully loaded into + memory, it becomes as master copy. Master copies of objects may be + cloned but not used as actual game objects. The master copy is used to + support any clone objects in the game. + + The master copy is the source of one of the controversies of mud LPC + coding, that is whether to clone or inherit. With rooms, there is no + question of what you wish to do, since there should only be one instance + of each room object in the game. So you generally use inheritance in + creating rooms. Many mud administrators, including myself, however + encourage creators to clone the standard monster object and configure it + from inside room objects instead of keeping monsters in separate files + which inherit the standard monster object. + + As I stated above, each time a file is referenced to create an object, a + master copy is loaded into memory. When you do something like: + void reset() { + object ob; + ob = new("/std/monster"); + /* clone_object("/std/monster") some places */ + ob->SetKeyName("foo monster"); + ... rest of monster config code followed by moving + it to the room ... + } + the driver searches to see if their is a master object called "/std/monster". + If not, it creates one. If it does exist, or after it has been created, the + driver then creates a clone object called "/std/monster#<number>". If + this is the first time "/std/monster" is being referenced, in effect, two + objects are being created: the master object and the cloned instance. + + On the other hand, let's say you did all your configuring in the create() + of a special monster file which inherits "/std/monster". Instead of + cloning the standard monster object from your room, you clone your + monster file. If the standard monster has not been loaded, it gets loaded + since your monster inherits it. In addition, a master copy of your file + gets loaded into memory. Finally, a clone of your monster is created + and moved into the room, for a total of three objects added to the game. + Note that you cannot make use of the master copy easily to get around + this. If, for example, you were to do: + "/realms/descartes/my_monster"->eventMove(this_object()); + instead of + new("/realms/descartes/my_monster")->eventMove(this_object()); + you would not be able to modify the file "my_monster.c" and update it, + since the update command destroys the current master version of an + object. On some mudlibs it also loads the new version into memory. + Imagine the look on a player's face when their monster disappears in + mid-combat cause you updated the file! + + Cloning is therefore a useful too when you plan on doing just that- + cloning. If you are doing nothing special to a monster which cannot be + done through a few call others, then you will save the mud from getting + loaded with useless master copies. Inheritance, however, is useful if + you plan to add functionality to an object (write your own functions) or + if you have a single configuration that gets used over and over again + (you have an army of orc guards all the same, so you write a special orc + file and clone it). + + 6.3 Inside Inheritance + When objects A and B inherit object C, all three objects have their own + set of data sharing one set of function definitions from object C. In + addition, A and B will have separate functions definitions which were + entered separately into their code. For the sake of example throughout + the rest of the chapter, we will use the following code. Do not be + disturbed if, at this point, some of the code makes no sense: + + STD_ITEM C + private string name, cap_name, short, long; + private int setup; + + void SetKeyName(string str) + nomask string GetKeyName(); + private int query_setup(); + static void unsetup(); + void SetShort(string str); + string GetShort(); + void SetLong(string str); + string GetLong(); + + + void SetKeyName(string str) { + if(!query_setup()) { + name = str; + setup = 1; + } + + nomask string GetKeyName() { return name; } + + private query_setup() { return setup; } + + static void unsetup() { setup = 0; } + + string GetName() { + return (name ? capitalize(name) : ""); } + } + + void SetShort(string str) { short = str; } + + string GetShort() { return short; } + + void SetLong(string str) { long = str; } + + string GetLong() { return str; } + + void create() { seteuid(getuid()); } + + STD_ITEM B + inherit "/std/objectc"; + + private int wc; + + void set_wc(int wc); + int query_wc(); + int wieldweapon(string str); + + void create() { ::create(); } + + void init() { + if(environment(this_object()) == this_player()) + add_action("wieldweapon", "wield"); + } + + void set_wc(int x) { wc = x; } + + int query_wc() { return wc; } + + int wieldweapon(string str) { + ... code for wielding the weapon ... + } + + STD_ITEM A + inherit "/std/objectc"; + + int ghost; + + void create() { ::create(); } + + void change_name(string str) { + if(!((int)this_object()->is_player())) unsetup(); + SetKeyName(str); + } + + string GetName() { + if(ghost) return "A ghost"; + else return ::GetName(); + } + + As you can see, object C is inherited both by object A and object B. + Object C is a representation of a much oversimplified base object, with B + being an equally oversimplified weapon and A being an equally + simplified living object. Only one copy of each function is retained in + memory, even though we have here three objects using the functions. + There are of course, three instances of the variables from Object C in + memory, with one instance of the variables of Object A and Object B in + memory. Each object thus gets its own data. + + 6.4 Function and Variable Labels + Notice that many of the functions above are proceeded with labels which + have not yet appeared in either this text or the beginner text, the labels + static, private, and nomask. These labels define special priveledges + which an object may have to its data and member functions. Functions + you have used up to this point have the default label public. This is + default to such a degree, some drivers do not support the labeling. + + A public variable is available to any object down the inheritance tree + from the object in which the variable is declared. Public variables in + object C may be accessed by both objects A and B. Similarly, public + functions may be called by any object down the inheritance tree from the + object in which they are declared. + + The opposite of public is of course private. A private variable or + function may only be referenced from inside the object which declares it. + If object A or B tried to make any reference to any of the variables in + object C, an error would result, since the variables are said to be out of + scope, or not available to inheriting classes due to their private labels. + Functions, however, provide a unique challenge which variables do not. + External objects in LPC have the ability to call functions in other objects + through call others. The private label does not protect against call + others. + + To protect against call others, functions use the label static. A function + which is static may only be called from inside the complete object or + from the game driver. By complete object, I mean object A can call + static functions in the object C it inherits. The static only protects against + external call others. In addition, this_object()->foo() is considered an + internal call as far as the static label goes. + + Since variables cannot be referenced externally, there is no need for an + equivalent label for them. Somewhere along the line, someone decided + to muddy up the waters and use the static label with variables to have a + completely separate meaning. What is even more maddening is that this + label has nothing to do with what it means in the C programming + language. A static variable is simply a variable that does not get saved to + file through the efun save_object() and does not get restored through + restore_object(). Go figure. + + In general, it is good practice to have private variables with public + functions, using query_*() functions to access the values of inherited + variables, and set_*(), add_*(), and other such functions to change + those values. In realm coding this is not something one really has to + worry a lot about. As a matter of fact, in realm coding you do not have + to know much of anything which is in this chapter. To be come a really + good realm coder, however, you have to be able to read the mudlib + code. And mudlib code is full of these labels. So you should work + around with these labels until you can read code and understand why it + is written that way and what it means to objects which inherit the code. + + The final label is nomask, and it deals with a property of inheritance + which allows you to rewrite functions which have already been defined. + For example, you can see above that object A rewrote the function + GetName(). A rewrite of function is called overriding the + function. The most common override of a function would be in a case + like this, where a condition peculiar to our object (object A) needs to + happen on a call ot the function under certain circumstances. Putting test + code into object C just so object A can be a ghost is plain silly. So + instead, we override GetName() in object A, testing to see if the + object is a ghost. If so, we change what happens when another object + queries for the cap name. If it is not a ghost, then we want the regular + object behaviour to happen. We therefore use the scope resolution + operator (::) to call the inherited version of the GetName() + function and return its value. + + A nomask function is one which cannot be overridden either through + inheritance or through shadowing. Shadowing is a sort of backwards + inheritance which will be detailed in the advanced LPC textbook. In the + example above, neither object A nor object B (nor any other object for + that matter) can override GetKeyName(). Since we want to use + GetKeyName() as a unique identifier of objects, we don't want people + faking us through shadowing or inheritance. The function therefore gets + the nomask label. + + 6.5 Summary + Through inheritance, a coder may make user of functions defined in + other objects in order to reduce the tedium of producing masses of + similar objects and to increase the consistency of object behaviour across + mudlib objects. LPC inheritance allows objects maximum priveledges in + defining how their data can be accessed by external objects as well as + objects inheriting them. This data security is maintained through the + keywords, nomask, private, and static. + + In addition, a coder is able to change the functionality of non-protected + functions by overriding them. Even in the process of overriding a + function, however, an object may access the original function through + the scope resolution operator. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/manual/chapter15 ds2.1/lib/doc/manual/chapter15 *** ds1.1/lib/doc/manual/chapter15 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter15 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,299 ---- + chapter 15 "Debugging" + Intermediate LPC + Descartes of Borg + November 1993 + + Chapter 7: Debugging + + 7.1 Types of Errors + By now, you have likely run into errors here, there, and everywhere. In + general, there are three sorts of errors you might see: compile time + errors, run time errors, and malfunctioning code. On most muds you + will find a personal file where your compile time errors are logged. For + the most part, this file can be found either in your home directory as the + file named "log" or ".log", or somewhere in the directory "/log" as a file + with your name.. In addition, muds tend to keep a log of run time errors + which occur while the mud is up. Again, this is generally found in + "/log". On MudOS muds it is called "debug.log". On other muds it may + be called something different like "lpmud.log". Ask your administrators + where compile time and run time errors are each logged if you do not + already know. + + Compile time errors are errors which occur when the driver tries to load + an object into memory. If, when the driver is trying to load an object + into memory, it encounters things which it simply does not understand + with respect to what you wrote, it will fail to load it into memory and log + why it could not load the object into your personal error log. The most + common compile time errors are typos, missing or extra (), {}. [], or "", + and failure to declare properly functions and variables used by the + object. + + Run time errors occur when something wrong happens to an object in + memory while it is executing a statement. For example, the driver + cannot tell whether the statement "x/y" will be valid in all circumstances. + In fact, it is a valid LPC expression. Yet, if the value of y is 0, then a + run time error will occur since you cannot divide by 0. When the driver + runs across an error during the execution of a function, it aborts + execution of the function and logs an error to the game's run time error + log. It will also show the error to this_player(), if defined, if the player + is a creator, or it will show "What?" to players. Most common causes + for run time errors are bad values and trying to perform operations with + data types for which those operations are not defined. + + The most insideous type of error, however, is plain malfunctioning + code. These errors do not log, since the driver never really realizes that + anything is wrong. In short, this error happens when you think the code + says one thing, but in fact it says another thing. People too often + encounter this bug and automatically insist that it must be a mudlib or + driver bug. Everyone makes all types of errors though, and more often + than not when code is not functioning the way you should, it will be + because you misread it. + + 7.2 Debugging Compile Time Errors + Compile time errors are certainly the most common and simplest bugs to + debug. New coders often get frustrated by them due to the obscure + nature of some error messages. Nevertheless, once a person becomes + used to the error messages generated by their driver, debugging compile + time errors becomes utterly routine. + + In your error log, the driver will tell you the type of error and on which + line it finally noticed there was an error. Note that this is not on which + line the actual error necessarily exists. The most common compile time + error, besides the typo, is the missing or superfluous parentheses, + brackets, braces, or quotes. Yet this error is the one that most baffles + new coders, since the driver will not notice the missing or extra piece + until well after the original. Take for example the following code: + + 1 int test(string str) { + 2 int x; + 3 for(x =0; x<10; x++) + 4 write(x+"\n"); + 5 } + 6 write("Done.\n"); + 7 } + + Depending on what you intended, the actual error here is either at line 3 + (meaning you are missing a {) or at line 5 (meaing you have an extra }). + Nevertheless, the driver will report that it found an error when it gets to + line 6. The actual driver message may vary from driver to driver, but no + matter which driver, you will see an error on line 6, since the } in line 5 + is interpreted as ending the function test(). At line 6, the driver sees that + you have a write() sitting outside any function definition, and thus + reports an error. Generally, the driver will also go on to report that it + found an error at line 7 in the form of an extra }. + + The secret to debugging these is coding style. Having closing } match + up vertically with the clauses they close out helps you see where you are + missing them when you are debugging code. Similarly, when using + multiple sets of parentheses, space out different groups like this: + if( (x=sizeof(who=users()) > ( (y+z)/(a-b) + (-(random(7))) ) ) + As you can see, the parentheses for the for() statement, are spaced out + from the rest of the statement. In addition, individual sub-groups are + spaced so they can easily be sorted out in the event of an error. + + Once you have a coding style which aids in picking these out, you learn + which error messages tend to indicate this sort of error. When + debugging this sort of error, you then view a section of code before and + after the line in question. In most all cases, you will catch the bug right + off. + + Another common compile time error is where the driver reports an + unknown identifier. Generally, typos and failure to declare variables + causes this sort of error. Fortunately, the error log will almost always + tell you exactly where the error is. So when debugging it, enter the + editor and find the line in question. If the problem is with a variable and + is not a typo, make sure you declared it properly. On the other hand, if + it is a typo, simply fix it! + + One thing to beware of, however, is that this error will sometimes be + reported in conjunction with a missing parentheses, brackets, or braces + type error. In these situations, your problem with an unknown identifier + is often bogus. The driver misreads the way the {} or whatever are + setup, and thus gets variable declarations confused. Therefore make + sure all other compile time errors are corrected before bothering with + these types of errors. + + In the same class with the above error, is the general syntax error. The + driver generates this error when it simply fails to understand what you + said. Again, this is often caused by typos, but can also be caused by not + properly understanding the syntax of a certain feature like writing a for() + statement: for(x=0, x<10, x++). If you get an error like this which is + not a syntax error, try reviewing the syntax of the statement in which the + error is occurring. + + 7.3 Debugging Run Time Errors + Run time errors are much more complex than their compile time + counterparts. Fortunately these errors do get logged, though many + creators do not realise or they do not know where to look. The error log + for run time errors are also generally much more detailed than compile + time errors, meaning that you can trace the history of the execution train + from where it started to where it went wrong. You therefore can setup + debugging traps using precompiler statements much easier using these + logs. Run time errors, however, tend to result from using more + complex codign techniques than beginners tend to use, which means you + are left with errors which are generally more complicated than simple + compile time errors. + + Run time errors almost always result from misusing LPC data types. + Most commonly, trying to do call others using object variables which are + NULL, indexing on mapping, array, or string variables which are + NULL, or passing bad arguments to functions. We will look at a real + run time error log from Nightmare: + + Bad argument 1 to explode() + program: bin/system/_grep.c, object: bin/system/_grep + line 32 + ' cmd_hook' in ' std/living.c' (' + std/user#4002')line 83 + ' cmd_grep' in ' bin/system/_grep.c' (' + bin/system/_grep')line 32 + Bad argument 2 to message() + program: adm/obj/simul_efun.c, object: adm/obj/simul_efun + line 34 + ' cmd_hook' in ' std/living.c' (' + std/user#4957')line 83 + ' cmd_look' in ' bin/mortal/_look.c' (' + bin/mortal/_look')line 23 + ' examine_object' in ' bin/mortal/_look.c' (' + bin/mortal/_look')line 78 + ' write' in 'adm/obj/simul_efun.c' (' + adm/obj/simul_efun')line 34 + Bad argument 1 to call_other() + program: bin/system/_clone.c, object: bin/system/_clone + line 25 + ' cmd_hook' in ' std/living.c' (' + std/user#3734')line 83 + ' cmd_clone' in ' bin/system/_clone.c' (' + bin/system/_clone')line 25 + Illegal index + program: std/monster.c, object: + wizards/zaknaifen/spy#7205 line 76 + ' heart_beat' in ' std/monster.c' + ('wizards/zaknaifen/spy#7205')line + 76 + + All of the errors, except the last one, involve passing a bad argument to a + function. The first bug, involves passing a bad first arument to the efun + explode(). This efun expects a string as its first argment. In debugging + these kinds of errors, we would therefore go to line 32 in + /bin/system/_grep.c and check to see what the data type of the first + argument being passed in fact is. In this particular case, the value being + passed should be a string. + + If for some reason I has actually passed something else, I would be done + debugging at that point and fix it simply by making sure that I was + passing a string. This situation is more complex. I now need to trace + the actual values contained by the variable being passed to explode, so + that I can see what it is the explode() efun sees that it is being passed. + + The line is question is this: + borg[files[i]] = regexp(explode(read_file(files[i]), "\n"), exp); + where files is an array for strings, i is an integer, and borg is a mapping. + So clearly we need to find out what the value of read_file(files[i]) is. + Well, this efun returns a string unless the file in question does not exist, + the object in question does not have read access to the file in question, or + the file in question is an empty file, in which cases the function will + return NULL. Clearly, our problem is that one of these events must + have happened. In order to see which, we need to look at files[i]. + + Examining the code, the files array gets its value through the get_dir() + efun. This returns all the files in a directory if the object has read access + to the directory. Therefore the problem is neither lack of access or non- + existent files. The file which caused this error then must have been an + empty file. And, in fact, that is exactly what caused this error. To + debug that, we would pass files through the filter() efun and make + sure that only files with a file size greater than 0 were allowed into the + array. + + The key to debugging a run time error is therefore knowing exactly what + the values of all variables in question are at the exact moment where the + bug created. When reading your run time log, be careful to separate the + object from the file in which the bug occurred. For example, the + indexing error above came about in the object /wizards/zaknaifen/spy, + but the error occured while running a function in /std/monster.c, which + the object inherited. + + 7.4 Malfunctioning Code + The nastiest problem to deal with is when your code does not behave the + way you intended it to behave. The object loads fine, and it produces no + run time errors, but things simply do not happen the way they should. + Since the driver does not see a problem with this type of code, no logs + are produced. You therefore need to go through the code line by line + and figure out what is happening. + + Step 1: Locate the last line of code you knew successfully executed + Step 2: Locate the first line of code where you know things are going + wrong + Step 3: Examine the flow of the code from the known successful point to + the first known unsuccessful point. + + More often than not, these problems occurr when you are using if() + statements and not accounting for all possibilities. For example: + + int cmd(string tmp) { + if(stringp(tmp)) return do_a() + else if(intp(tmp)) return do_b() + return 1; + } + + In this code, we find that it compiles and runs fine. Problem is nothing + happens when it is executed. We know for sure that the cmd() function + is getting executed, so we can start there. We also know that a value of + 1 is in fact being returned, since we do not see "What?" when we enter + the command. Immediately, we can see that for some reason the + variable tmp has a value other than string or int. As it turns out, we + issued the command without parameters, so tmp was NULL and failed + all tests. + + The above example is rather simplistic, bordering on silly. + Nevertheless, it gives you an idea of how to examine the flow of the + code when debugging malfunctioning code. Other tools are available as + well to help in debugging code. The most important tool is the use of + the precompiler to debug code. With the code above, we have a clause + checking for integers being passed to cmd(). When we type "cmd 10", + we are expecting do_b() to execute. We need to see what the value of + tmp is before we get into the loop: + + #define DEBUG + int cmd(string tmp) { + #ifdef DEBUG + write(tmp); + #endif + if(stringp(tmp)) return do_a(); + else if(intp(tmp)) return do_b(); + else return 1; + } + + We find out immediately upon issuing the command, that tmp has a + value of "10". Looking back at the code, we slap ourselves silly, + forgetting that we have to change command arguments to integers using + sscanf() before evaluating them as integers. + + 7.5 Summary + The key to debugging any LPC problem is always being aware of what + the values of your variables are at any given step in your code. LPC + execution reduces on the simplest level to changes in variable values, so + bad values are what causes bad things to happen once code has been + loaded into memory. If you get errors about bad arguments to + functions, more likely than not you are passing a NULL value to a + function for that argument. This happens most often with objects, since + people will do one of the following: + 1) use a value that was set to an object that has since destructed + 2) use the return value of this_player() when there is no this_player() + 3) use the return value of this_object() just after this_object() was + destructed + + In addition, people will often run into errors involving illegal indexing or + indexing on illegal types. Most often, this is because the mapping or + array in question was not initialized, and therefore cannot be indexed. + The key is to know exactly what the full value of the array or mapping + should be at the point in question. In addition, watch for using index + numbers larger than the size of given arrays + + Finally, make use of the precompiler to temporarly throw out code, or + introduce code which will show you the values of variables. The + precompiler makes it easy to get rid of debugging code quickly once you + are done. You can simply remove the DEBUG define when you are + done. + + Copyright (c) George Reese 1993 diff -c -r --new-file ds1.1/lib/doc/manual/chapter16 ds2.1/lib/doc/manual/chapter16 *** ds1.1/lib/doc/manual/chapter16 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter16 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,181 ---- + chapter 16 "Armor" + Building Armours + The Nightmare IV LPC Library + written by Descartes of Borg 950430 + + Armour has changed quite a bit from the days of armour class. The + Nightmare IV LPC Library now uses damage types, which means armour that + is great against one attack may be pathetic against another. In fact, + in building armour, it is important that you keep in mind weaknesses. + Fortunately, armour is by default absolutely pathetic. If you go + making it awesome, chances are that it will not make it through the + approval process. This document is designed to get you started + building armour as well introduce you to the features available to + make unique and interesting armour. + + I. Basic Armour + You should be familiar with /doc/build/Items, as armour is just a + special type of item. It therefore has all of the features of regular + items. + + + + The basic armour looks like this: + + #include <lib.h> /* see this everywhere */ + #include <armour_types.h> /* a listing of armour types */ + #include <damage_types.h> /* a listing of damage types */ + + inherit LIB_ARMOUR; /* the armour inheritable */ + + static void create() { + armour::create(); /* call create() in armour.c */ + SetKeyName("rusty helm"); + SetId( ({ "helm", "rusty helm", "a rusty helm" }) ); + SetAdjectives( ({ "rusty" }) ); + SetShort("a rusty helm"); + SetLong("A rusty helmet which will be better than nothing on your head."); + SetMass(75); + SetValue(200); + SetDamagePoints(1000); + SetProtection(BLUNT, 4); /* SetProtection() sets the sort of */ + SetProtection(BLADE, 3); /* protection for a given damage type */ + SetProtection(KNIFE, 3); + SetArmourType(A_HELMET); /* set what kind of armour this is */ + } + + As you can see, there is very little that you have to do specific to + armour. The only armour specific call you MUST make is + SetArmourType(). Everything else is fluff. + + int SetArmourType(int type) + Armour types are found in /include/armour_types.h. The armour type + basically determines where the armour is worn. Each monster, + depending on its race, has for each limb a list of armour types which + may be worn on that limb. For example, most monsters have heads. + Some have two heads. You do not have to worry about this. They know + that they can wear anything that is A_HELMET on their heads. What if + you have something that may not be wearable on all monsters? Like, + for example, you have body armour which should only go on two armed + beings? See SetRestrictLimbs() later. It allows you to restrict + exactly which kinds of limbs can wear the armour. + + int SetProtection(int type, int amount); + Without this call, armour is nothing. Just something you wear. This + allows you to make clothes, which may protect against COLD, but do not + do a thing when struck with a sword. Protection is a number between 0 + and 100. Refer to approval documentation for details on what levels + are appropriate, as well as for information on mass and value levels. + + That's it for the basics! + + II. Advanced Function Calls + The Nightmare IV LPC Library armour object is fairly flexible for + allowing you to do interesting things with your armours. In this + section, you will learn about other function calls you can make to + customize your armour. + + string *SetRestrictLimbs(string *limbs); + Example: + SetRestrictLimbs( ({ "right arm", "left arm", "torso" }) ); + + For armours which can only be on certain body configurations, for + example regular armour (A_ARMOUR) should only be worn on people with + the same number of hands, this function allows you to restrict the + armour to being worn only on the limbs you name. If the person trying + to wear the armour does not have one of those limbs, any attempt to + wear fails. + + int SetFingers(int num); + Example: + SetFingers(5); + + Used for the glove types. If a person has more fingers on the limb on + which they are trying to wear a glove type than the glove has spaces + for, the wear fails. + + mixed SetWear(string | function val); + Examples: + SetWear("The cloak feels all yucky on you."); + SetWear( (: CheckArtrell :) ); + + Allows you to create a special message seen by the person wearing the + item when they wear it if you pass a string. On the other hand, if + you pass a function, it will call that function to see if the person + can wear the item. The function should be of the form: + int WearFunc(); + + For example: + + int CheckArtrell() { + if( (string)this_player()->GetRace() == "artrell" ) { + write("The rusty helm makes you feel safe."); + say((string)this_player()->GetName() + " wears a rusty helm."); + return 1; + } + else { + write("You cannot wear that you bum!"); + return 1; + } + } + + III. Function Overrides + The only function of interest that you might want to override is a + function called eventReceiveDamage(). This function is called every + time the armour is hit to see how much of the damage it absorbs. It + looks like this: + + int eventReceiveDamage(int type, int strength, int unused, mixed limbs); + + This function is called by combat to determine how much damage the + armour absorbs for a given bit of damage being done. It thus should + return how much damage it takes. + + You should always at some point call item::eventReceiveDamage() so + that it can do its processing. You do not want to call it, however, + until you determine how much damage you are absorbing unnaturally. + Here is a sample one for an armour that does extra protection for fighters: + + int eventReceiveDamage(int type, int strength, int blah, mixed limbs) { + object who_is_wearing; + int x; + + if( !(who_is_wearing = environment()) ) /* eek! no one wearing */ + return 0; + if( (int)who_is_wearing->ClassMember("fighter") ) /* reduce strength */ + x = strength - random(5); + if( x < 1 ) return strength; /* protect against all the damage */ + return armour::eventReceiveDamage(type, x, blah, limbs); + } + + Keep in mind what eventReceiveDamage() in armour.c is doing. First, + it is modifying the strength of the blow based on the protections you + set with SetProtection(). Then, it is having the armour take damage + based on how much it absorbed. So you need to call + eventReceiveDamage() in armour at the point where you have a value you + want the armour to do its normal stuff with. In the example above, we + wanted to magically protect fighters against a random(5) points of + damage without having the armour take any damage for that. Then if + there is still strength left in the blow, the armour does its normal + protection. + + What else can you do with this? Imagine an armour that turns all cold + damage back on the attacker? + + int eventReceiveDamage(int type, int strength, int unused, mixed limbs) { + object who_wearing, enemy; + + enemy = (object)(who_wearing = previous_object())->GetCurrentEnemy(); + if( !enemy || !(type & COLD) ) + return armour::eventReceiveDamage(type, strength, unused, limbs); + limbs = enemy->GetTargetLimb(0); + message("environment", "Your anti-cold throws the frost in your " + "enemy's face!", who_wearing); + message("environment", "Your cold attack is turned back upon you!", + enemy); + enemy->eventReceiveDamage(COLD, strength, unused, limbs); + return strength; /* we absorb all of the strength but take no damage */ + } + + Descartes of Borg + borg@imaginary.com diff -c -r --new-file ds1.1/lib/doc/manual/chapter17 ds2.1/lib/doc/manual/chapter17 *** ds1.1/lib/doc/manual/chapter17 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter17 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,68 ---- + chapter 17 "Barkeeps" + Building Food and Drink Sellers + The Nightmare IV LPC Library + written by Descartes of Borg 950528 + + This document details the building of barkeeps, waiters, and other + such people who sell food and drink. Barkeeps are NPC's, and + therefore everythign which applies to NPC's applies to barkeeps. + + To build a barkeep, you should inherit LIB_BARKEEP. + + Beyond the functions specific to NPC's barkeeps also make use of the + following functions: + + mapping SetMenuItems(mapping menu); + mapping AddMenuItem(string item, string file); + mapping RemoveMenuItem(string item); + mapping GetMenuItems(); + string SetLocalCurrency(string curr); + + When building a barkeep, you must add some mechanism in the room in + which the barkeep is placed for people to view a list of things for + sale. + + ***** + mapping SetMenuItems(mapping menu); + ***** + + Example: SetMenuItems( ([ "coffee" : "/realms/descartes/coffee" ]) ); + + Sets which menu items are found in which file. This is a mapping with + the name of the item as a key and the file in which it is located as + the value. + + ***** + mapping AddMenuItem(string item, string file); + ***** + + Example: AddMenuItem("lobster", "/realms/descartes/lobster"); + + Adds one menu item at a time to the list of menu items. + + ***** + mapping RemoveMenuItem(string item); + ***** + + Example: RemoveMenuItem("coffee"); + + Removes the named item from the menu. + + ***** + mapping GetMenuItems(); + ***** + + Returns all the menu items for this barkeep. Useful in building your + menu list. + + ***** + string SetLocalCurrency(string curr); + ***** + + Example: SetLocalCurrency("khucha"); + + Sets the currency in which the barkeep does business. + + + + diff -c -r --new-file ds1.1/lib/doc/manual/chapter18 ds2.1/lib/doc/manual/chapter18 *** ds1.1/lib/doc/manual/chapter18 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter18 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,8 ---- + chapter 18 "Valid climates" + + indoors + temperate + arid + arctic + tropical + sub-tropical diff -c -r --new-file ds1.1/lib/doc/manual/chapter19 ds2.1/lib/doc/manual/chapter19 *** ds1.1/lib/doc/manual/chapter19 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter19 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,263 ---- + chapter 19 "Doors" + Creating Doors between Two Rooms + The Nightmare IV LPC Library + created by Descartes of Borg 950419 + + This document describes how to build door-type objects which link two + rooms. These door-type objects do not need to be doors, but in fact + can be windows or boulders or any other such object. The Nightmare IV + LPC Library door object, unlike the old way of doing doors, is an + object separate from the rooms it connects. In other words, in order + to build a door, you have three objects (just as you would visualize): + two rooms and a door. + + The door object is /lib/door.c. To inherit it, #include <lib.h> and + inherit LIB_DOOR;. An example door may be found in + /domains/Examples/etc/door.c as well as the rooms + /domains/Examples/room/doorroom1.c and /domains/Examples/room/doorroom2.c. + + Setting up the door object + The first thing you must do is create the door object. You must + visualize this door object just like a door connecting two rooms in + real life. You have a room on each side with a single door with two + sides. Technically, a door object may have any number of sides. + Practically speaking, most people using this object will be using it + as a door, which means it will have two sides. + + To create a door object, you simply describe each side of the door. + The easiest way to do this is through the SetSide() function. + + mapping SetSide(string side, mapping mp); + + Example: + + SetSide("east", ([ "id" : "red door", "short" : "a red door", + "long" : "A freshly painted red door.", + "lockable" : 0 ]) ); + + The name of the side is simply the exit used by the room which sees + that side. For example, if in one room the door is at the east exit, + then the side is identified as east. The mapping consists of the + following data: + + "id" + What a person on that side calls the door. For example, you can have a + door blue on one side and red on the other. On one side, you go east + to go through the door, and from that room the door appears red. The + id for that side might be "red door". The id for the other side might + be "blue door". + + "short" + The short description for the door as seen from the side in question. + This can be a function or a string. + + "long" + The long description for the door as seen from the side in question. + Whether the door is open or not will be added to the long if the long + is a string. This can be either a string or function. If it is a + function, you must specify whether the door is open or close on your + own. + + "lockable" + 0 if the door cannot be locked (and unlocked) from that side, 1 if it + can. + + "keys" + An array of id's of objects which can be used to unlock it if it is + lockable. Lockable doors do not need keys. + + II. Setting up the rooms + After you have called SetItems() and SetExits() in the room + (remembering to set the exit for the exit with the door), call the + function SetDoor(). + + string SetDoor(string dir, string doorfile); + + Example: SetDoor("east", "/realms/descartes/doors/red_door"); + + Sets the exit named to be blocked by a door object when that door + object is closed. + + This is all you need to do in the room. Note that the exit name + corresponds to the side name mentioned in the door. + + III. Advanced Door Stuff + At this point, you should know how to do the minimum stuff to build a + door. This section goes into detail about door functions and how you + can do advanced things with doors by manipulating door events. This + section has two parts, door data functions and door events. + + a. Door Data Functions + + ***** + SetSide() + ***** + mapping SetSide(string side, mapping mp); + + As described above. + + ***** + SetClosed() + ***** + static int SetClosed(int x) + + Example: SetClosed(1); + + This function can only be called from inside the door object. + Generally you use it to set the initial state of the door. If you + want to close the door at any other time, or to close it from another + object, use eventClose() or eventOpen(). + + ***** + SetLocked() + ***** + + static int SetLocked(int x) + + Example: SetLocked(1); + + Like SetClosed(), this function should only be used from create() + inside the door object to set the initial state of the door. At other + times, use eventLock() or eventUnlock(). + + ***** + SetLockable() + ***** + + int SetLockable(string side, int x) + + Example: SetLockable("east", 1); + + Sets a side as being able to be locked or unlocked. Since it is done + by sides, this means you can have one side not be lockable with the + other side being lockable. The first argument is the side being set + lockable or not lockable, the second argument is 1 for lockable and 0 + for not lockable. + + ***** + SetId() + ***** + + string SetId(string side, string id) + + Example: SetId("west", "blue door"); + + This is not like your traditional SetId() function. Instead, it sets + a single way of identifying the door from a given side. It is what + the player might use to open the door or look at it. + + ***** + SetShort() + ***** + + mixed SetShort(string side, string | function desc) + + Examples: + SetShort("north", "a red door"); + SetShort("west", (: GetWestShort :) ); + + Sets the short description for a given side of a door. If the second + argument is a function, it gets passed as an argument the name of the + side for which the function serves as a description. That function + should return a string. For the above: + + string GetWestShort(string dir) { + if( query_night() ) return "a shadowy door"; + else return "a red door"; + } + + ***** + SetLong() + ***** + + mixed SetLong(string side, string | function desc) + + Examples: + SetLong("south", "An old, dusty door covered in cobwebs."); + SetLong("east", (: GetEastLong :)) + + This works much like the SetShort() function, except it handles the + long description. It is important to note that if the second argument + is a string, that the state of the door will be added onto the long + description automatically. In other words "It is open." will appear + as the second line. This will *not* be done if you use a function for + your long description. + + ***** + SetKeys() + ***** + + string *SetKeys(string side, string *keys) + + Example: SetKeys("east", ({ "skeleton key", "special key" })); + + Builds an array of id's which can be used to unlock the door if it is + lockable from this side. In other words, a person can only unlock the + door if that person has an object which has one of the id's you + specify for its id. + + b. Events + + ***** + eventOpen() + ***** + + varargs int eventOpen(object by, object agent) + + Examples: + + "/realms/descartes/etc/red_door"->eventOpen(this_object()); + + int eventOpen(object by, object agent) { + if( query_night() ) return 0; /* Can't open it at night */ + else return door::eventOpen(by, agent); + } + + The function that actually allows the door to be opened externally. + It returns 1 if the door is successfully opened. It returns 0 if it + fails. The first argument is the room object from which the door is + being opened. The second argument, which is optional, is the living + thing responsible for opening the door. + + The first example above is an example of what you might do from + reset() inside a room in order to have the door start open at every + reset. + + The second example above is an example of how you might conditionally + prevent the door from opening by overriding the Open event. In this + case, if it is night, you cannot open this door. If it is day, you + can. + + ***** + eventClose() + ***** + + varargs int eventClose(object by, object agent) + + Example: See eventOpen() + + This function works just like eventOpen(), except it does the closing + of the door. + + ***** + eventLock() + ***** + + varargs int eventLock(object by, object agent) + + Example: see eventOpen() + + This function works just like eventOpen(), except that it gets called + for locking the door. + + ***** + eventUnlock() + ***** + + varargs int eventUnlock(object by, object agent) + + Example: See eventOpen() + + This function works just like eventOpen(), except that it gets called + for unlocking the door. + diff -c -r --new-file ds1.1/lib/doc/manual/chapter20 ds2.1/lib/doc/manual/chapter20 *** ds1.1/lib/doc/manual/chapter20 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter20 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,368 ---- + chapter 20 "Items" + Building Any Item + The Nightmare IV LPC Library + written by Descartes of Borg 950430 + + Each object you build has a certain common make-up no matter what type + of object it is. This is because all of your objects actually are + based upon the same object, the object called /lib/object.c. That + object contains functions such as SetShort() and SetLong() which you + use in almost every single object you will build. This document + details how to set up any possible object you will use. The only + exceptions will be for rooms, which do not have key names or id's. + + Beyond that, most of the every day objects you will code like armours, + weapons, drinks, foods, etc. all derive from a common object called + /lib/item.c. This document attempts to detail what is involved in + building any object on the MUD through /lib/item.c and its ancestor + /lib/object.c. + + This document is in three sections + + I. List of Mandatory Function Calls + II. Basic Functions + III. Extras + IV. Events + + ** *************** List of Mandatory Function Calls ************** ** + + SetKeyName("red bag"); + SetId( ({ "bag", "red bag" }) ); + SetAdjectives( ({ "red" }) ); + SetShort("a red bag"); + SetLong("A small red bag with no distinguishing marks."); + SetMass(90); + SetValue(50); + SetVendorType(VT_BAG); + + You also need to include vendor_types.h. + + ** *************** Basic Functions *************** ** + + ***** + SetKeyName() + ***** + + string SetKeyName(string key_name); + + Example: SetKeyName("red bag"); + + Notes: + Mandatory for all objects except rooms. + Not used for rooms. + + The key name is the central name by which the object is referred to in + sentences where no article is required. For example, the sentence + "You pick up your red bag" makes use of the key name to complete the + sentence. This is much like the short description, except the short + description will include an article. For this object, SetShort("a red + bag") would be used. + + ***** + SetId() + ***** + + string *SetId(string *id); + + Example: SetId( ({ "bag", "red bag" }) ); + + Notes: + Mandatory for all objects except rooms. + Not used in rooms. + Must be all lower case. + + The id is an array of strings by which the object may be referred to by a + player. For example, if the player wants to get this bag, the player + can type "get bag" or "get red bag". The id is used purely for + identification purposes, so if you have something you need to sneak in + a unique way of identifying it, you may add an id only you know about. + + ***** + SetAdjectives() + ***** + + string *SetAdjectives(string *adjs); + + Example: SetAdjectives( ({ "red" }) ); + + Notes: + Planned for future use in Zork style command parsing. + Not used in rooms. + + The adjectives are descriptive terms used to describe the object. + This is not currently being used, however, it will be part of the new + style command parsing we will be building. This will allow the player + to type things like "get the red one" and pick up the red bag. Even + though it is not used, it is requested you place it in your objects to + make upgrading down the road a simpler task. + + ***** + SetShort() + ***** + + string SetShort(string description | function desc_func); + + Examples: + SetShort("a red bag"); + SetShort((: DescribeBag :)); + + The short description is a brief description of the object. Only + names and proper nouns should be capitalized, the rest should be lower + case, as if it were appearing in the middle of a sentence. In rooms, + the player sees the short description when in brief mode and when they + glance at the room. For objects, the player sees the short when it is + described in the room or in their inventory. + + If you pass a function instead of a string, then that function is used + to create the description. You can use this to do something like make + the object change its short description depending on who is looking at + it. The function that you build should therefore return a string + that will be used as the short description. For example... + + string DescribeBag() { + if( query_night() ) return "a bag"; + else return "a red bag"; + } + + ***** + SetLong() + ***** + + string SetLong(string description | function desc_func); + + Examples: + SetLong("A red bag with no markings on it whatsoever."); + SetLong((: BagLong :)); + + Creates a verbose way to present the object to the player. You should + be much more descriptive than I have been in the example. Being a + text game, descriptions are 90% of what make the game. The more + creative you are with your descriptions, the more interesting the game + is to players. The long description of a room is seen by players in + verbose mode and when the player uses the "look" command. For + objects, the long description is seen when the player looks at the + object. Functions work in exactly the same fashion as short + functions. + + ***** + SetMass() + ***** + + int SetMass(int mass); + + Example: SetMass(100); + + Notes: + Mandatory for all visible objects. + Not needed for non-tangible objects and rooms. + + Sets the mass for the object. In conjunction with the gravity of the + room it is in, this works to determine the weight of the object. + + ***** + SetValue() + ***** + + int SetValue(int value); + + Example: SetValue(50); + + Notes: + Mandatory for all sellable objects. + Not used in rooms. + + Sets the base economic value of an object. This has no meaning in any + currencies, and in fact the actual value in any given currency may + vary. + + ***** + SetVendorType() + ***** + + int SetVendorType(int vt); + + Example: SetVendorType(VT_BAG); + + Note: + Mandatory for all objects except rooms. + Preset to VT_ARMOUR for objects which inherit LIB_ARMOUR. + Preset to VT_TREASURE for objects which inherit LIB_ITEM. + Preset to VT_LIGHT for objects which inherit LIB_LIGHT. + Not valid for room objects. + Values are found in /include/vendor_types.h. + + You must do: + #include <vendor_types.h> + to use the VT_* macros (i.e. VT_ARMOUR, VT_TREASURE, VT_WEAPON). + + The vendor type determines which shops will buy the item. For + example, things with VT_BAG as the vendor type can be bought and sold + in bag stores. For items which cross the line, for example a flaming + sword, you can combine vendor types in the following manner: + SetVendorType(VT_WEAPON | VT_LIGHT); + + ***** + SetDamagePoints() + ***** + + int SetDamagePoints(int pts); + + Example: SetDamagePoints(500) + + Sets the amount of damage an object can take before descreasing in + value. With armours and weapons, damage is taken quite often. Damage + is more rare with other kinds of objects. With this example object + which has 500 damage points, whenever 500 points has been done to it, + its value is cut in half and eventDeteriorate() is called for the + object. See the events section on using eventDeteriorate(). The + points are then reset to 500 and damage is done from that. + + ** *************** Extras *************** ** + + ***** + SetProperty() + ***** + + mixed SetProperty(string property, mixed value); + + Example: SetProperty("no pick", 1); + + Allows you to store information in an object which may not have been + intended by the designer of the object, or which is fleeting in + nature. See /doc/build/Properties for a list of common properties. + ***** + SetProperties() + ***** + + mapping SetProperties(mapping props); + + Example: SetProperties( ([ "light" : 1, "no attack" : 1 ]) ); + + Allows you to set any properties you want all in one shot. + + ***** + SetDestroyOnSell() + ***** + + int SetDestroyOnSell(int true_or_false); + + Example: SetDestroyOnSell(1); + + For mundane objects, or objects which should not be resold, allows you + to set it so that the object gets destroyed when sold instead of + allowing it to be resold. + + ***** + SetPreventGet() + ***** + + mixed SetPreventGet(mixed val); + + Examples: + SetPreventGet("You cannot get that!"); + SetPreventGet( (: check_get :) ); + + Allows you to make an object un-gettable by a player. If you pass a + string, the player will see that string any time they try to get the + item. If you pass a function, that function will be called to see if + you want to allow the get. Your function gets the person trying to get + the object as an argument: + + int check_get(object who) { + if( (int)who->GetRave() == "ogre" ) { + message("my_action", "Ogres cannot get this thing!", who); + return 0; + } + else return 1; + } + + ***** + SetPreventPut() + ***** + + mixed SetPreventPut(mixed val); + + Examples: + SetPreventPut("You cannot put that in there!"); + SetPreventPut( (: check_put :) ); + + The same as SetPreventGet(), except this is used when the object is + being put into another object. + + ***** + SetPreventDrop() + ***** + + mixed SetPreventDrop(mixed val); + + Examples: + SetPreventDrop("You cannot drop that!"); + SetPreventDrop( (: check_drop :) ); + + The same as SetPreventGet(), except this is used when a player tries + to drop the object. + + + ** *************** General Events ************** ** + + ***** + eventDeteriorate() + ***** + + void eventDeteriorate(int type); + + Example: ob->eventDeteriorate(COLD); + + Notes: + Damage types can be found in /include/damage_types.h + + This function gets called periodically in objects whenever they wear + down a bit. The type passed to the function is the type of damage + which triggered the deterioration. + + ***** + eventMove() + ***** + + int eventMove(mixed dest); + + Example: + ob->eventMove(this_player()); + ob->eventMove("/domains/Praxis/square"); + + The eventMove event is called in an object when it is being moved from + one place to the next. You can either pass it the file name of a room + to which it should be moved or an object into which it should be + moved. It will return true if the object gets moved, false if it + cannot move for some reason. For objects which are being dropped, + gotten, or put, it is generally a good idea to check CanDrop(), + CanClose(), or CanGet() for the object in question since eventMove() + does not know the context of the move and therefore will allow a drop + since it does not check CanDrop(). + + ***** + eventReceiveDamage() + ***** + + varargs int eventReceiveDamage(int type, int amount, int unused, mixed limbs); + + Example: ob->eventReceiveDamage(BLUNT, 30, 0, "right hand"); + + This function gets called in an object whenever any damage is done to + it. Most frequently this gets called in monsters and armour. In + armour you can use it to modify the amount of damage which gets done. + The return value of this function is the amount of damage done to the + object. For example, if you have a piece of armour that absorbs 5 of + the 30 points listed above, then you return 5. + + NOTE: + For monsters there is an extra arg at the front called + agent. The agent is the being responsible for doing + the damage. It may be zero if something like the weather + is causing the damage. It looks like: + + varargs int eventReceiveDamage(object agent, int type, int strength, + int internal, mixed limbs); + + For more detailed information, see /doc/build/NPC. + diff -c -r --new-file ds1.1/lib/doc/manual/chapter21 ds2.1/lib/doc/manual/chapter21 *** ds1.1/lib/doc/manual/chapter21 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter21 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,151 ---- + chapter 21 "Meals" + Building Food and Drink Objects + The Nightmare IV LPC Library + written by Descartes of Borg 950603 + + This document details the creation of food and drinks using the + Nightmare LPC Library. The creation of barkeeper objects requires you + to be able to build these objects, so make sure you understand what is + going on in here before moving on to barkeepers. + + To create food or drink, you inherit from the standard meal object + /lib/meal.c For example: + + #include <lib.h> + + inherit LIB_MEAL; + + You have access to the same functions you have in generic items when + you build food and drinks. In particular, you should be sure to call + the following: + + SetKeyName() + SetId() + SetShort() + SetLong() + SetMass() + + Note that SetValue() does NOTHING for food and drinks. Value is + automatically determined by the strength of the item. + + The following function calls are specific to "meal" objects: + + int SetMealType(int types); + int SetStrength(int strength); + + mixed *SetMealMessages(function f); + OR + mixed *SetMealmessages(string mymsg, string othermsg); + + string SetEmptyName(string str); + string SetEmptyShort(string str); + string SetEmptyLong(string str); + string SetEmptyItem(string str); + + You must call SetMealType(), SetStrength(), and SetMealMessages(). + If you call SetEmptyItem(), you do not need to call the functions + SetEmptyName(), SetEmptyShort(), SetEmptyLong(). On the other hand, + if you do not call SetEmptyItem(), you do need to set the other three. + + ***** + int SetMealType(int types) + ***** + + Example: SetMealType(MEAL_FOOD); + + For meal objects, you must do: + + #include <meal_types.h> + + This includes all od the definitions for the meal types in + /include/meal_types.h into your food or drink. You need these + definitions when setting what type of meal object this is. The types + are: + + MEAL_FOOD + MEAL_DRINK + MEAL_CAFFEINE + MEAL_ALCOHOL + MEAL_POISON + + In general, almost anything you create will be at least either + MEAL_FOOD or MEAL_DRINK. You can add onto it using the | operator. + For example, to make an alcoholic drink: + + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + + This makes something a drink and an alcoholic drink. You want to + stick poison in it? + + SetMealType(MEAL_DRINK | MEAL_ALCOHOL | MEAL_POISON); + + ***** + int SetStrength(int x) + ***** + + Example: SetStrength(20); + + This sets how strong your food or drink is. It affects things like + which people can drink or eat it and how much the drink or food costs. + Refer to balance documents to see what is good. + + ***** + varargs mixed *SetMealMessages(function|string, string) + ***** + + Examples: + SetMealMessages((: call_other(find_object("/some/object"),"drink") :)); + SetMealmessages("You drink your beer.", "$N drinks $P beer."); + + You can pass a single argument, which is a function to be called. + This function will be called after the person has drank or eaten the + meal. It gives you a chance to do some bizarre messaging and such. + + If you pass two strings, the first string is used as a message to send + to the player doing the drinking, and the second is what everyone else + sees. To make the message versatile, you can put in the following + place holders: + + $N the name of the drinker/eater + $P his/her/its + + For example: + $N drinks $P beer. + might resolve to: + Descartes drinks his beer. + + ***** + string SetEmptyName(string str) + ***** + + Example: SetEmptyName("bottle"); + + Sets an id from the empty container of drinks. This need not be set + for food. + + ***** + string SetEmptyShort(string str) + ***** + + Example: SetEmptyShort("an empty bottle") + + Sets what the short description of the empty container is for anything + that is of type MEAL_DRINK. + + ***** + string SetEmptyLong(string str) + ***** + + Example: SetEmptyLong("A brown bottle that used to contain beer."); + + Sets the long description for the empty container for drink objects. + + ***** + string SetEmptyItem(string str) + ***** + + Example: SetEmptyItem("/domains/Praxis/etc/empty_bottle") + + Instead of cloning a generic empty object and setting the other empty + functions, you can create a special empty container which gets given + to the player after they drink a drink object. Not relevant to food. diff -c -r --new-file ds1.1/lib/doc/manual/chapter22 ds2.1/lib/doc/manual/chapter22 *** ds1.1/lib/doc/manual/chapter22 Wed Dec 31 19:00:00 1969 --- ds2.1/lib/doc/manual/chapter22 Wed Jul 5 00:01:03 2006 *************** *** 0 **** --- 1,285 ---- + chapter 22 "NPCs" + Building Non-Player Characters + The Nightmare IV Object Library + written by Descartes of Borg 951201 + + This document outlines the creation of non-player characters (NPC's). + On other muds, NPC's are sometimes referred to as monsters. Like the + rooms document, this document is divided up into two sections: basic + NPC building and complex NPC building. NPC's are living things which + inherit all the behaviours of living things. Documentation on living + specific functionality may be found in /doc/build/Livings. + + ************************************************ + Part 1: Basic NPC Building + ************************************************ + + ***** + I. The simplest NPC + ***** + + #include <lib.h> + + inherit LIB_NPC; + + static void create() { + npc::create(); + SetKeyName("praxis peasant"); + SetId( ({ "peasant", "praxis peasant" }) ); + SetShort("a local peasant"); + SetLong("Dirty and totally disheveled, this poor inhabitant of Praxis " + "still somehow maintains an air of dignity that nothing can " + "break."); + SetLevel(1); + SetRace("elf"); + SetClass("fighter"); + SetGender("male"); + } + + There are two things you should note. The first is that an NPC is + also a general object, meaning that you have available to you all the + things you can do with general objects, like setting descriptions and + ID's. The second is that a basic NPC does not require a heck of a lot + more. I will cover the NPC specific functions here. + + SetLevel(1) + SetRace("elf") + SetClass("fighter") + Level, race, and class are the three most important settings in any + NPC. Together they determine how powerful the NPC is. You are + absolutely required to set a level and a race. For those who + absolutely do not want to give the NPC a class, you do not have to. + But, you must instead manually set the NPC's skill levels, which is + described in the second part of this document. In general, however, + you always want to set the class. + + Together, the class and race and level determine which skills and + stats are considered important for the monster, and how good at those + skills and stats the monster is. The order in which you call these + functions is irrelevant, as everything is recalculated any time one of + the above changes. + + Also, note that SetRace() may only be called with a race listed in the + mraces command with simple NPC's. If you wish to build an NPC with a + unique race, you need to do some limb manipulation, which is described + in the advanced section. + + SetGender("male") + While not required, you will normally want to give an NPC a gender. + The default is neutral. However, in this world, very little is + neuter. Your choices for this function are male, female, and neuter. + + ***** + II. Other NPC Configuration Functions + ***** + + Function: int SetMorality(int amount); + Example: SetMorality(100); + + This is a number between -2000 and 2000 which determines the morality + of an individual with respect to good and evil. -2000 is absolute + evil, and 2000 is absolute good. The actions of players determine + their morality, and often those actions are relative to a target. + Thus killing an evil being can be considered good, while killing a bad + one evil. + + Function: int SetUnique(int x); + Example: SetUnique(1) + + Marks the NPC as a unique monster. This allows the room which clones + your NPC to use the negative values to SetInventory() (see + /doc/build/Rooms) to make sure the NPC only gets cloned every few + days. + + ************************************************ + Part 2: Advanced NPC Building + ************************************************ + + ***** + I. Functions + ***** + + You may use these functions to make your NPC's a bit more interesting + than the simple variety. + + Function: void SetAction(int chance, mixed val); + Examples: SetAction(5, (: DoSomething :)); + SetAction(5, ({ "!smile", "!frown" })); + SetAction(5, ({ "The peasant looks unhappy." })); + + Sets something to randomly happen every few heart beats while the NPC + is not in combat. In the above examples, the NPC has a 5% chance each + heart beat of performing the action you provided with the second + argument. The action can be a call to a function, a list of potential + commands, or a list of strings to be echoed to the room. + + If you pass a function, that function will be called each time an + action is supposed to occur. If you pass a list of strings, one of + those strings will be randomly chosen as the target action for this + heart beat. If the chosen string begins with a !, it is treated as a + command. Otherwise, it is simply echoed to the room. Note that you + can mix commands and echo strings. + + ***** + + Function: void SetCombatAction(int chance, mixed val); + Examples: SetCombatAction(5, (: DoSomething :)); + SetCombatAction(5, ({ "!missile", "!fireball" })); + SetAction(5, ({ "The peasant looks angry." })); + + This function works exactly the same as SetAction(), except that these + actions only get triggered while the NPC is in combat. This is the + best place to have the NPC cast spells. + + ***** + + Function: varargs void SetCurrency(mixed val, int amount); + Examples: SetCurrency("gold", 100); + SetCurrency( ([ "gold" : 100, "electrum" : 1000 ]) ); + + This function allows you to set how much money an NPC is carrying. + The first syntax allows you to set one currency at a time. The second + allows you to set multiple currencies at once. Not that if you use + the second syntax, it will blow away any currencies the NPC might + already be carrying. + + ***** + + Function: mixed SetDie(mixed val); + Examples: SetDie("The black knight bleeds on you as he drops dead."); + SetDie((: CheckDie :)); + + If you pass a string, that string will be echoed as the NPC's death + message when it dies. If you pass a function, that function gets + called with the agent doing the killing, if any, as an argument. For + example, with the above example, the function that you write: + + int CheckDie(object killer); + + gets called. If you return 1, the NPC goes on to die. If you return + 0, the NPC does not die. In the event you prevent death, you need to + make some arrangements with the NPC's health points and such to make + sure it really is still alive. + + ***** + + Function: mixed SetEncounter(mixed val); + Examples: SetEncounter(40); + SetEncounter( (: CheckDwarf :) ); + SetEncounter( ({ str1, str2 }) ); + + This allows you to set up e behaviour for an NPC upon encountering + another living thing. Note that this behaviour occurrs for both + players and other NPC's. Using the first syntax, the NPC will simply + attack any other living thing with a charisma less than 40. The + second syntax calls the function you specify. You may have it do any + number of things, however, you must also return a 1 or a 0 from that + function. A 1 means that after the function is called, the NPC should + initiate combat against the thing it just encountered. A 0 means + carry on as usual. + + Finally, the third syntax is likely to be used in places other than + the create() funciton in the NPC. This syntax lets you set a list + names which are simply enemies to the NPC. More likely, you will be + using AddEncounter() and RemoveEncounter() for this. + + ***** + + Function: string *AddEncounter(string name); + Example: AddEncounter((string)this_player()->GetKeyName()); + + Adds a name to the list of names an NPC will attack on sight. + + ***** + + Function: string *RemoveEncounter(string name); + Example: RemoveEncounter((string)this_player()->GetKeyName()); + + Removes a name from the list of names an NPC will attack on sight. + + ***** + + Function: SetInventory(mapping inventory); + Examples: + SetInventory( ([ "/domains/Praxis/weapon/sword" : "wield sword" ]) ); + SetInventory( ([ "/domains/Praxix/etc/ruby" : 1 ]) ); + SetInventory( ([ "/domains/Praxis/etc/emerald" : -10 ]) ); + + This functions behaves almost identically to SetInventory() for rooms + (see /doc/build/Rooms). The big difference is that you may pass a + string in addition to a number as the value for any item you want in + the inventory. In the first example above, that string is the command + the NPC issues when the sword is cloned into its inventory. In other + words, if you want an NPC to do something special with an item it has + in its inventory, in this case wield the sword, you pass the command + string as the value instead of a number. + + Note that this means only one of such item will be cloned, and it + cannot be unique. + + ***** + II. Events + ***** + + The following events exist in NPC's. You should have a good grasp of + function overriding before overriding these functions. + + Event: varargs int eventDie(object target); + + This event is triggered any time the NPC is killed. The event returns + 1 if the NPC dies, 0 if it fails to die, and -1 on error. If you + intend to allow the NPC to die, you should call npc::eventDie(target) + and make sure it returns 1. + + ***** + + Event: int eventFollow(object dest, int chance); + + This event is triggered whenever an NPC is following another living + thing and that thing leaves the room. Returnung 1 means that the NPC + successfully followed the other being, and 0 means the NPC did not. + + ***** + 3. Manipulating limbs + ***** + + The basic set of limbs an NPC gets is generally set when you set its + race. You can get a list of supported NPC races through the mraces + command. Occassionally, however, you may want to create NPCs of + unique races, or with unique body structures. Or perhaps you want a + human whose right hand is already amputated. This section deals with + doing those things. + + Amputating a limb is simple. Call RemoveLimb("limb"). Note that that + is not useful for removing a limb that should not be there. Instead, + it is used for amputating a limb that looks amputated. + + If, on the other hand, you wish to remove a limb which simply should + not have been there in the first place, call DestLimb("limb"). + + The most simple case of actual limb manipulation, however, is to + change the basic structure of an individual NPC around for some + reason. For example, perhaps you wanted to add a tail to a human. + For this, you use the AddLimb() function. + + Function: varargs int AddLimb(string limb, string parent, int class, int *armours); + Examples: AddLimb("tail", "torso", 4) + AddLimb("head", "torso", 1, ({ A_HELMET, A_VISOR, A_AMULET })); + + This function adds a new limb to the NPC's body. The first argumen